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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [serial/] [arm/] [aeb/] [current/] [src/] [aeb_serial.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      io/serial/arm/aeb_serial.c
4
//
5
//      ARM AEB-1 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 Free Software Foundation, 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      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):   gthomas
43
// Contributors:  gthomas
44
// Date:        1999-02-04
45
// Purpose:     AEB-1 Serial I/O module (interrupt driven version)
46
// Description: 
47
//
48
//####DESCRIPTIONEND####
49
//
50
//==========================================================================
51
 
52
#include <pkgconf/system.h>
53
#include <pkgconf/io_serial.h>
54
#include <pkgconf/io.h>
55
#include <cyg/io/io.h>
56
#include <cyg/hal/hal_intr.h>
57
#include <cyg/io/devtab.h>
58
#include <cyg/io/serial.h>
59
#include <cyg/infra/diag.h>
60
 
61
#ifdef CYGPKG_IO_SERIAL_ARM_AEB
62
 
63
#include "aeb_serial.h"
64
 
65
typedef struct aeb_serial_info {
66
    CYG_ADDRWORD   base;
67
    CYG_WORD       int_num;
68
    cyg_interrupt  serial_interrupt;
69
    cyg_handle_t   serial_interrupt_handle;
70
} aeb_serial_info;
71
 
72
static bool aeb_serial_init(struct cyg_devtab_entry *tab);
73
static bool aeb_serial_putc(serial_channel *chan, unsigned char c);
74
static Cyg_ErrNo aeb_serial_lookup(struct cyg_devtab_entry **tab,
75
                                   struct cyg_devtab_entry *sub_tab,
76
                                   const char *name);
77
static unsigned char aeb_serial_getc(serial_channel *chan);
78
static Cyg_ErrNo aeb_serial_set_config(serial_channel *chan,
79
                                       cyg_uint32 key,
80
                                       const void *xbuf, cyg_uint32 *len);
81
static void aeb_serial_start_xmit(serial_channel *chan);
82
static void aeb_serial_stop_xmit(serial_channel *chan);
83
 
84
static cyg_uint32 aeb_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
85
static void       aeb_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
86
 
87
static SERIAL_FUNS(aeb_serial_funs,
88
                   aeb_serial_putc,
89
                   aeb_serial_getc,
90
                   aeb_serial_set_config,
91
                   aeb_serial_start_xmit,
92
                   aeb_serial_stop_xmit
93
    );
94
 
95
#ifdef CYGPKG_IO_SERIAL_ARM_AEB_SERIAL0
96
static aeb_serial_info aeb_serial_info0 = {0xFFFF0000,
97
                                           CYGNUM_HAL_INTERRUPT_UART0};
98
#if CYGNUM_IO_SERIAL_ARM_AEB_SERIAL0_BUFSIZE > 0
99
static unsigned char aeb_serial_out_buf0[CYGNUM_IO_SERIAL_ARM_AEB_SERIAL0_BUFSIZE];
100
static unsigned char aeb_serial_in_buf0[CYGNUM_IO_SERIAL_ARM_AEB_SERIAL0_BUFSIZE];
101
 
102
static SERIAL_CHANNEL_USING_INTERRUPTS(aeb_serial_channel0,
103
                                       aeb_serial_funs,
104
                                       aeb_serial_info0,
105
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AEB_SERIAL0_BAUD),
106
                                       CYG_SERIAL_STOP_DEFAULT,
107
                                       CYG_SERIAL_PARITY_DEFAULT,
108
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
109
                                       CYG_SERIAL_FLAGS_DEFAULT,
110
                                       &aeb_serial_out_buf0[0], sizeof(aeb_serial_out_buf0),
111
                                       &aeb_serial_in_buf0[0], sizeof(aeb_serial_in_buf0)
112
    );
113
#else
114
static SERIAL_CHANNEL(aeb_serial_channel0,
115
                      aeb_serial_funs,
116
                      aeb_serial_info0,
117
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AEB_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(aeb_serial_io0,
126
             CYGDAT_IO_SERIAL_ARM_AEB_SERIAL0_NAME,
127
             0,                     // Does not depend on a lower level interface
128
             &cyg_io_serial_devio,
129
             aeb_serial_init,
130
             aeb_serial_lookup,     // Serial driver may need initializing
131
             &aeb_serial_channel0
132
    );
133
#endif //  CYGPKG_IO_SERIAL_ARM_AEB_SERIAL0
134
 
135
#ifdef CYGPKG_IO_SERIAL_ARM_AEB_SERIAL1
136
static aeb_serial_info aeb_serial_info1 = {0xFFFF0400,
137
                                           CYGNUM_HAL_INTERRUPT_UART1};
138
#if CYGNUM_IO_SERIAL_ARM_AEB_SERIAL1_BUFSIZE > 0
139
static unsigned char aeb_serial_out_buf1[CYGNUM_IO_SERIAL_ARM_AEB_SERIAL1_BUFSIZE];
140
static unsigned char aeb_serial_in_buf1[CYGNUM_IO_SERIAL_ARM_AEB_SERIAL1_BUFSIZE];
141
 
142
static SERIAL_CHANNEL_USING_INTERRUPTS(aeb_serial_channel1,
143
                                       aeb_serial_funs,
144
                                       aeb_serial_info1,
145
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AEB_SERIAL1_BAUD),
146
                                       CYG_SERIAL_STOP_DEFAULT,
147
                                       CYG_SERIAL_PARITY_DEFAULT,
148
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
149
                                       CYG_SERIAL_FLAGS_DEFAULT,
150
                                       &aeb_serial_out_buf1[0], sizeof(aeb_serial_out_buf1),
151
                                       &aeb_serial_in_buf1[0], sizeof(aeb_serial_in_buf1)
152
    );
153
#else
154
static SERIAL_CHANNEL(aeb_serial_channel1,
155
                      aeb_serial_funs,
156
                      aeb_serial_info1,
157
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AEB_SERIAL1_BAUD),
158
                      CYG_SERIAL_STOP_DEFAULT,
159
                      CYG_SERIAL_PARITY_DEFAULT,
160
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
161
                      CYG_SERIAL_FLAGS_DEFAULT
162
    );
163
#endif
164
 
165
DEVTAB_ENTRY(aeb_serial_io1,
166
             CYGDAT_IO_SERIAL_ARM_AEB_SERIAL1_NAME,
167
             0,                     // Does not depend on a lower level interface
168
             &cyg_io_serial_devio,
169
             aeb_serial_init,
170
             aeb_serial_lookup,     // Serial driver may need initializing
171
             &aeb_serial_channel1
172
    );
173
#endif //  CYGPKG_IO_SERIAL_ARM_AEB_SERIAL1
174
 
175
// Internal function to actually configure the hardware to desired baud rate, etc.
176
static bool
177
aeb_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
178
{
179
    aeb_serial_info *aeb_chan = (aeb_serial_info *)chan->dev_priv;
180
    volatile struct serial_port *port = (volatile struct serial_port *)aeb_chan->base;
181
    unsigned short baud_divisor = select_baud[new_config->baud];
182
    unsigned char _lcr, _ier;
183
    if (baud_divisor == 0) return false;
184
    _ier = port->REG_IER;
185
    port->REG_IER = 0;  // Disable port interrupts while changing hardware
186
    _lcr = select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
187
        select_stop_bits[new_config->stop] |
188
        select_parity[new_config->parity];
189
    port->REG_LCR = _lcr;
190
    port->REG_LCR |= LCR_DL;
191
    port->REG_MDL = baud_divisor >> 8;
192
    port->REG_LDL = baud_divisor & 0xFF;
193
    port->REG_LCR &= ~LCR_DL;
194
    if (init) {
195
        port->REG_FCR = 0x07;  // Enable and clear FIFO
196
        if (chan->out_cbuf.len != 0) {
197
            port->REG_IER = IER_RCV;
198
        } else {
199
            port->REG_IER = 0;
200
        }
201
        port->REG_MCR = MCR_INT|MCR_DTR|MCR_RTS;  // Master interrupt enable
202
    } else {
203
        port->REG_IER = _ier;
204
    }
205
    if (new_config != &chan->config) {
206
        chan->config = *new_config;
207
    }
208
    return true;
209
}
210
 
211
// Function to initialize the device.  Called at bootstrap time.
212
static bool
213
aeb_serial_init(struct cyg_devtab_entry *tab)
214
{
215
    serial_channel *chan = (serial_channel *)tab->priv;
216
    aeb_serial_info *aeb_chan = (aeb_serial_info *)chan->dev_priv;
217
#ifdef CYGDBG_IO_INIT
218
    diag_printf("AEB SERIAL init - dev: %x.%d\n", aeb_chan->base, aeb_chan->int_num);
219
#endif
220
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
221
    if (chan->out_cbuf.len != 0) {
222
        cyg_drv_interrupt_create(aeb_chan->int_num,
223
                                 99,                     // Priority - unused
224
                                 (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
225
                                 aeb_serial_ISR,
226
                                 aeb_serial_DSR,
227
                                 &aeb_chan->serial_interrupt_handle,
228
                                 &aeb_chan->serial_interrupt);
229
        cyg_drv_interrupt_attach(aeb_chan->serial_interrupt_handle);
230
        cyg_drv_interrupt_unmask(aeb_chan->int_num);
231
    }
232
    aeb_serial_config_port(chan, &chan->config, true);
233
    return true;
234
}
235
 
236
// This routine is called when the device is "looked" up (i.e. attached)
237
static Cyg_ErrNo
238
aeb_serial_lookup(struct cyg_devtab_entry **tab,
239
                  struct cyg_devtab_entry *sub_tab,
240
                  const char *name)
241
{
242
    serial_channel *chan = (serial_channel *)(*tab)->priv;
243
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
244
    return ENOERR;
245
}
246
 
247
// Send a character to the device output buffer.
248
// Return 'true' if character is sent to device
249
static bool
250
aeb_serial_putc(serial_channel *chan, unsigned char c)
251
{
252
    aeb_serial_info *aeb_chan = (aeb_serial_info *)chan->dev_priv;
253
    volatile struct serial_port *port = (volatile struct serial_port *)aeb_chan->base;
254
    if (port->REG_LSR & LSR_THE) {
255
// Transmit buffer is empty
256
        port->REG_THR = c;
257
        return true;
258
    } else {
259
// No space
260
        return false;
261
    }
262
}
263
 
264
// Fetch a character from the device input buffer, waiting if necessary
265
static unsigned char
266
aeb_serial_getc(serial_channel *chan)
267
{
268
    unsigned char c;
269
    aeb_serial_info *aeb_chan = (aeb_serial_info *)chan->dev_priv;
270
    volatile struct serial_port *port = (volatile struct serial_port *)aeb_chan->base;
271
    while ((port->REG_LSR & LSR_RSR) == 0) ;   // Wait for char
272
    c = port->REG_RHR;
273
    return c;
274
}
275
 
276
// Set up the device characteristics; baud rate, etc.
277
static Cyg_ErrNo
278
aeb_serial_set_config(serial_channel *chan, cyg_uint32 key,
279
                      const void *xbuf, cyg_uint32 *len)
280
{
281
    switch (key) {
282
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
283
      {
284
        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
285
        if ( *len < sizeof(cyg_serial_info_t) ) {
286
            return -EINVAL;
287
        }
288
        *len = sizeof(cyg_serial_info_t);
289
        if ( true != aeb_serial_config_port(chan, config, false) )
290
            return -EINVAL;
291
      }
292
      break;
293
    default:
294
        return -EINVAL;
295
    }
296
    return ENOERR;
297
}
298
 
299
// Enable the transmitter on the device
300
static void
301
aeb_serial_start_xmit(serial_channel *chan)
302
{
303
    aeb_serial_info *aeb_chan = (aeb_serial_info *)chan->dev_priv;
304
    volatile struct serial_port *port = (volatile struct serial_port *)aeb_chan->base;
305
    port->REG_IER |= IER_XMT;  // Enable xmit interrupt
306
}
307
 
308
// Disable the transmitter on the device
309
static void
310
aeb_serial_stop_xmit(serial_channel *chan)
311
{
312
    aeb_serial_info *aeb_chan = (aeb_serial_info *)chan->dev_priv;
313
    volatile struct serial_port *port = (volatile struct serial_port *)aeb_chan->base;
314
    port->REG_IER &= ~IER_XMT;  // Disable xmit interrupt
315
}
316
 
317
// Serial I/O - low level interrupt handler (ISR)
318
static cyg_uint32
319
aeb_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
320
{
321
    serial_channel *chan = (serial_channel *)data;
322
    aeb_serial_info *aeb_chan = (aeb_serial_info *)chan->dev_priv;
323
    cyg_drv_interrupt_mask(aeb_chan->int_num);
324
    cyg_drv_interrupt_acknowledge(aeb_chan->int_num);
325
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
326
}
327
 
328
// Serial I/O - high level interrupt handler (DSR)
329
static void
330
aeb_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
331
{
332
    serial_channel *chan = (serial_channel *)data;
333
    aeb_serial_info *aeb_chan = (aeb_serial_info *)chan->dev_priv;
334
    volatile struct serial_port *port = (volatile struct serial_port *)aeb_chan->base;
335
    unsigned char isr;
336
    isr = port->REG_ISR & 0x0E;
337
    if (isr == ISR_Tx) {
338
        (chan->callbacks->xmt_char)(chan);
339
    } else if (isr == ISR_Rx) {
340
        (chan->callbacks->rcv_char)(chan, port->REG_RHR);
341
    }
342
    cyg_drv_interrupt_unmask(aeb_chan->int_num);
343
}
344
#endif

powered by: WebSVN 2.1.0

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