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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [devs/] [serial/] [arm/] [edb7xxx/] [v2_0/] [src/] [edb7xxx_serial.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      io/serial/arm/edb7xxx_serial.c
4
//
5
//      Cirrus Logic EDB7XXX 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
44
// Contributors:  gthomas
45
// Date:        1999-02-04
46
// Purpose:     EDB7XXX 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>
58
#include <cyg/io/devtab.h>
59
#include <cyg/io/serial.h>
60
#include <cyg/infra/diag.h>
61
 
62
#ifdef CYGPKG_IO_SERIAL_ARM_EDB7XXX
63
 
64
#include "edb7xxx_serial.h"
65
 
66
typedef struct edb7xxx_serial_info {
67
    CYG_ADDRWORD   data,                      // Pointer to data register
68
                   control,                   // Pointer to baud rate/line control register
69
                   stat,                      // Pointer to system flags for this port
70
                   syscon;                    // Pointer to system control for this port
71
    CYG_WORD       tx_int_num,                // Transmit interrupt number
72
                   rx_int_num,                // Receive interrupt number
73
                   ms_int_num;                // Modem Status Change interrupt number
74
    cyg_interrupt  serial_tx_interrupt,
75
                   serial_rx_interrupt,
76
                   serial_ms_interrupt;
77
    cyg_handle_t   serial_tx_interrupt_handle,
78
                   serial_rx_interrupt_handle,
79
                   serial_ms_interrupt_handle;
80
    bool           tx_enabled;
81
} edb7xxx_serial_info;
82
 
83
static bool edb7xxx_serial_init(struct cyg_devtab_entry *tab);
84
static bool edb7xxx_serial_putc(serial_channel *chan, unsigned char c);
85
static Cyg_ErrNo edb7xxx_serial_lookup(struct cyg_devtab_entry **tab,
86
                                   struct cyg_devtab_entry *sub_tab,
87
                                   const char *name);
88
static unsigned char edb7xxx_serial_getc(serial_channel *chan);
89
static Cyg_ErrNo edb7xxx_serial_set_config(serial_channel *chan, cyg_uint32 key,
90
                                           const void *xbuf, cyg_uint32 *len);
91
static void edb7xxx_serial_start_xmit(serial_channel *chan);
92
static void edb7xxx_serial_stop_xmit(serial_channel *chan);
93
 
94
static cyg_uint32 edb7xxx_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data);
95
static void       edb7xxx_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
96
static cyg_uint32 edb7xxx_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data);
97
static void       edb7xxx_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
98
static cyg_uint32 edb7xxx_serial_ms_ISR(cyg_vector_t vector, cyg_addrword_t data);
99
static void       edb7xxx_serial_ms_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
100
 
101
static SERIAL_FUNS(edb7xxx_serial_funs,
102
                   edb7xxx_serial_putc,
103
                   edb7xxx_serial_getc,
104
                   edb7xxx_serial_set_config,
105
                   edb7xxx_serial_start_xmit,
106
                   edb7xxx_serial_stop_xmit
107
    );
108
 
109
#ifdef CYGPKG_IO_SERIAL_ARM_EDB7XXX_SERIAL1
110
static edb7xxx_serial_info edb7xxx_serial_info1 = {UARTDR1, // Data register
111
                                                 UBLCR1,  // Port control
112
                                                 SYSFLG1, // Status
113
                                                 SYSCON1, // System config
114
                                                 CYGNUM_HAL_INTERRUPT_UTXINT1, // Tx interrupt
115
                                                 CYGNUM_HAL_INTERRUPT_URXINT1, // Rx interrupt
116
 
117
#if CYGNUM_IO_SERIAL_ARM_EDB7XXX_SERIAL1_BUFSIZE > 0
118
static unsigned char edb7xxx_serial_out_buf1[CYGNUM_IO_SERIAL_ARM_EDB7XXX_SERIAL1_BUFSIZE];
119
static unsigned char edb7xxx_serial_in_buf1[CYGNUM_IO_SERIAL_ARM_EDB7XXX_SERIAL1_BUFSIZE];
120
 
121
static SERIAL_CHANNEL_USING_INTERRUPTS(edb7xxx_serial_channel1,
122
                                       edb7xxx_serial_funs,
123
                                       edb7xxx_serial_info1,
124
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_EDB7XXX_SERIAL1_BAUD),
125
                                       CYG_SERIAL_STOP_DEFAULT,
126
                                       CYG_SERIAL_PARITY_DEFAULT,
127
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
128
                                       CYG_SERIAL_FLAGS_DEFAULT,
129
                                       &edb7xxx_serial_out_buf1[0], sizeof(edb7xxx_serial_out_buf1),
130
                                       &edb7xxx_serial_in_buf1[0], sizeof(edb7xxx_serial_in_buf1)
131
    );
132
#else
133
static SERIAL_CHANNEL(edb7xxx_serial_channel1,
134
                      edb7xxx_serial_funs,
135
                      edb7xxx_serial_info1,
136
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_EDB7XXX_SERIAL1_BAUD),
137
                      CYG_SERIAL_STOP_DEFAULT,
138
                      CYG_SERIAL_PARITY_DEFAULT,
139
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
140
                      CYG_SERIAL_FLAGS_DEFAULT
141
    );
142
#endif
143
 
144
DEVTAB_ENTRY(edb7xxx_serial_io1,
145
             CYGDAT_IO_SERIAL_ARM_EDB7XXX_SERIAL1_NAME,
146
             0,                     // Does not depend on a lower level interface
147
             &cyg_io_serial_devio,
148
             edb7xxx_serial_init,
149
             edb7xxx_serial_lookup,     // Serial driver may need initializing
150
             &edb7xxx_serial_channel1
151
    );
152
#endif //  CYGPKG_IO_SERIAL_ARM_EDB7XXX_SERIAL2
153
 
154
#ifdef CYGPKG_IO_SERIAL_ARM_EDB7XXX_SERIAL2
155
static edb7xxx_serial_info edb7xxx_serial_info2 = {UARTDR2, // Data register
156
                                                 UBLCR2,  // Port control
157
                                                 SYSFLG2, // Status
158
                                                 SYSCON2, // System config
159
                                                 CYGNUM_HAL_INTERRUPT_UTXINT2, // Tx interrupt
160
                                                 CYGNUM_HAL_INTERRUPT_URXINT2, // Rx interrupt
161
                                                 0};      // No modem control
162
#if CYGNUM_IO_SERIAL_ARM_EDB7XXX_SERIAL2_BUFSIZE > 0
163
static unsigned char edb7xxx_serial_out_buf2[CYGNUM_IO_SERIAL_ARM_EDB7XXX_SERIAL2_BUFSIZE];
164
static unsigned char edb7xxx_serial_in_buf2[CYGNUM_IO_SERIAL_ARM_EDB7XXX_SERIAL2_BUFSIZE];
165
 
166
static SERIAL_CHANNEL_USING_INTERRUPTS(edb7xxx_serial_channel2,
167
                                       edb7xxx_serial_funs,
168
                                       edb7xxx_serial_info2,
169
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_EDB7XXX_SERIAL2_BAUD),
170
                                       CYG_SERIAL_STOP_DEFAULT,
171
                                       CYG_SERIAL_PARITY_DEFAULT,
172
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
173
                                       CYG_SERIAL_FLAGS_DEFAULT,
174
                                       &edb7xxx_serial_out_buf2[0], sizeof(edb7xxx_serial_out_buf2),
175
                                       &edb7xxx_serial_in_buf2[0], sizeof(edb7xxx_serial_in_buf2)
176
    );
177
#else
178
static SERIAL_CHANNEL(edb7xxx_serial_channel2,
179
                      edb7xxx_serial_funs,
180
                      edb7xxx_serial_info2,
181
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_EDB7XXX_SERIAL2_BAUD),
182
                      CYG_SERIAL_STOP_DEFAULT,
183
                      CYG_SERIAL_PARITY_DEFAULT,
184
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
185
                      CYG_SERIAL_FLAGS_DEFAULT
186
    );
187
#endif
188
 
189
DEVTAB_ENTRY(edb7xxx_serial_io2,
190
             CYGDAT_IO_SERIAL_ARM_EDB7XXX_SERIAL2_NAME,
191
             0,                     // Does not depend on a lower level interface
192
             &cyg_io_serial_devio,
193
             edb7xxx_serial_init,
194
             edb7xxx_serial_lookup,     // Serial driver may need initializing
195
             &edb7xxx_serial_channel2
196
    );
197
#endif //  CYGPKG_IO_SERIAL_ARM_EDB7XXX_SERIAL2
198
 
199
// Internal function to actually configure the hardware to desired baud rate, etc.
200
static bool
201
edb7xxx_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
202
{
203
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
204
    volatile cyg_uint32 *syscon = (volatile cyg_uint32 *)edb7xxx_chan->syscon;
205
    volatile cyg_uint32 *blcfg = (volatile cyg_uint32 *)edb7xxx_chan->control;
206
    unsigned int baud_divisor = select_baud[new_config->baud];
207
    cyg_uint32 _lcr;
208
    if (baud_divisor == 0) return false;
209
    // Disable port interrupts while changing hardware
210
    _lcr = select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
211
        select_stop_bits[new_config->stop] |
212
        select_parity[new_config->parity] |
213
        UBLCR_FIFOEN | UART_BITRATE(baud_divisor);
214
#ifdef CYGDBG_IO_INIT
215
    diag_printf("Set CTL: %x = %x\n", blcfg, _lcr);
216
#endif
217
    *blcfg = _lcr;
218
    *syscon |= SYSCON1_UART1EN;
219
    if (new_config != &chan->config) {
220
        chan->config = *new_config;
221
    }
222
    return true;
223
}
224
 
225
// Function to initialize the device.  Called at bootstrap time.
226
static bool
227
edb7xxx_serial_init(struct cyg_devtab_entry *tab)
228
{
229
    serial_channel *chan = (serial_channel *)tab->priv;
230
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
231
#ifdef CYGDBG_IO_INIT
232
    diag_printf("EDB7XXX SERIAL init - dev: %x.%d\n", edb7xxx_chan->control, edb7xxx_chan->tx_int_num);
233
#endif
234
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
235
    if (chan->out_cbuf.len != 0) {
236
        cyg_drv_interrupt_create(edb7xxx_chan->tx_int_num,
237
                                 99,                     // Priority - unused
238
                                 (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
239
                                 edb7xxx_serial_tx_ISR,
240
                                 edb7xxx_serial_tx_DSR,
241
                                 &edb7xxx_chan->serial_tx_interrupt_handle,
242
                                 &edb7xxx_chan->serial_tx_interrupt);
243
        cyg_drv_interrupt_attach(edb7xxx_chan->serial_tx_interrupt_handle);
244
        cyg_drv_interrupt_mask(edb7xxx_chan->tx_int_num);
245
        edb7xxx_chan->tx_enabled = false;
246
    }
247
    if (chan->in_cbuf.len != 0) {
248
        cyg_drv_interrupt_create(edb7xxx_chan->rx_int_num,
249
                                 99,                     // Priority - unused
250
                                 (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
251
                                 edb7xxx_serial_rx_ISR,
252
                                 edb7xxx_serial_rx_DSR,
253
                                 &edb7xxx_chan->serial_rx_interrupt_handle,
254
                                 &edb7xxx_chan->serial_rx_interrupt);
255
        cyg_drv_interrupt_attach(edb7xxx_chan->serial_rx_interrupt_handle);
256
        cyg_drv_interrupt_unmask(edb7xxx_chan->rx_int_num);
257
    }
258
    edb7xxx_serial_config_port(chan, &chan->config, true);
259
    return true;
260
}
261
 
262
// This routine is called when the device is "looked" up (i.e. attached)
263
static Cyg_ErrNo
264
edb7xxx_serial_lookup(struct cyg_devtab_entry **tab,
265
                  struct cyg_devtab_entry *sub_tab,
266
                  const char *name)
267
{
268
    serial_channel *chan = (serial_channel *)(*tab)->priv;
269
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
270
    return ENOERR;
271
}
272
 
273
// Send a character to the device output buffer.
274
// Return 'true' if character is sent to device
275
static bool
276
edb7xxx_serial_putc(serial_channel *chan, unsigned char c)
277
{
278
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
279
    volatile cyg_uint8  *data = (volatile cyg_uint8  *)edb7xxx_chan->data;
280
    volatile cyg_uint32 *stat = (volatile cyg_uint32 *)edb7xxx_chan->stat;
281
    if ((*stat & SYSFLG1_UTXFF1) == 0) {
282
// Transmit buffer/FIFO is not full
283
        *data = c;
284
        return true;
285
    } else {
286
// No space
287
        return false;
288
    }
289
}
290
 
291
// Fetch a character from the device input buffer, waiting if necessary
292
static unsigned char
293
edb7xxx_serial_getc(serial_channel *chan)
294
{
295
    unsigned char c;
296
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
297
    volatile cyg_uint32 *data = (volatile cyg_uint32 *)edb7xxx_chan->data;
298
    volatile cyg_uint32 *stat = (volatile cyg_uint32 *)edb7xxx_chan->stat;
299
    while (*stat & SYSFLG1_URXFE1) ; // Wait for char
300
    c = *data;
301
    return c;
302
}
303
 
304
// Set up the device characteristics; baud rate, etc.
305
static Cyg_ErrNo
306
edb7xxx_serial_set_config(serial_channel *chan, cyg_uint32 key,
307
                          const void *xbuf, cyg_uint32 *len)
308
{
309
    switch (key) {
310
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
311
      {
312
        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
313
        if ( *len < sizeof(cyg_serial_info_t) ) {
314
            return -EINVAL;
315
        }
316
        *len = sizeof(cyg_serial_info_t);
317
        if ( true != edb7xxx_serial_config_port(chan, config, false) )
318
            return -EINVAL;
319
      }
320
      break;
321
    default:
322
        return -EINVAL;
323
    }
324
    return ENOERR;
325
}
326
 
327
// Enable the transmitter (interrupt) on the device
328
static void
329
edb7xxx_serial_start_xmit(serial_channel *chan)
330
{
331
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
332
    edb7xxx_chan->tx_enabled = true;
333
    cyg_drv_interrupt_unmask(edb7xxx_chan->tx_int_num);
334
}
335
 
336
// Disable the transmitter on the device
337
static void
338
edb7xxx_serial_stop_xmit(serial_channel *chan)
339
{
340
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
341
    cyg_drv_interrupt_mask(edb7xxx_chan->tx_int_num);
342
    edb7xxx_chan->tx_enabled = false;
343
}
344
 
345
// Serial I/O - low level Tx interrupt handler (ISR)
346
static cyg_uint32
347
edb7xxx_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data)
348
{
349
    serial_channel *chan = (serial_channel *)data;
350
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
351
    cyg_drv_interrupt_mask(edb7xxx_chan->tx_int_num);
352
    cyg_drv_interrupt_acknowledge(edb7xxx_chan->tx_int_num);
353
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
354
}
355
 
356
// Serial I/O - high level Tx interrupt handler (DSR)
357
static void
358
edb7xxx_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
359
{
360
    serial_channel *chan = (serial_channel *)data;
361
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
362
    (chan->callbacks->xmt_char)(chan);
363
    if (edb7xxx_chan->tx_enabled) {
364
        cyg_drv_interrupt_unmask(edb7xxx_chan->tx_int_num);
365
    }
366
}
367
 
368
// Serial I/O - low level Rx interrupt handler (ISR)
369
static cyg_uint32
370
edb7xxx_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
371
{
372
    serial_channel *chan = (serial_channel *)data;
373
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
374
    cyg_drv_interrupt_mask(edb7xxx_chan->rx_int_num);
375
    cyg_drv_interrupt_acknowledge(edb7xxx_chan->rx_int_num);
376
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
377
}
378
 
379
// Serial I/O - high level Rx interrupt handler (DSR)
380
static void
381
edb7xxx_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
382
{
383
    serial_channel *chan = (serial_channel *)data;
384
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
385
    volatile cyg_uint32 *datreg = (volatile cyg_uint32 *)edb7xxx_chan->data;
386
    volatile cyg_uint32 *stat = (volatile cyg_uint32 *)edb7xxx_chan->stat;
387
    while (!(*stat & SYSFLG1_URXFE1))
388
        (chan->callbacks->rcv_char)(chan, *datreg);
389
    cyg_drv_interrupt_unmask(edb7xxx_chan->rx_int_num);
390
}
391
 
392
// Serial I/O - low level Ms interrupt handler (ISR)
393
static cyg_uint32
394
edb7xxx_serial_ms_ISR(cyg_vector_t vector, cyg_addrword_t data)
395
{
396
    serial_channel *chan = (serial_channel *)data;
397
    edb7xxx_serial_info *edb7xxx_chan = (edb7xxx_serial_info *)chan->dev_priv;
398
    cyg_drv_interrupt_mask(edb7xxx_chan->ms_int_num);
399
    cyg_drv_interrupt_acknowledge(edb7xxx_chan->ms_int_num);
400
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
401
}
402
 
403
// Serial I/O - high level Ms interrupt handler (DSR)
404
static void
405
edb7xxx_serial_ms_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
406
{
407
}
408
#endif // CYGPKG_IO_SERIAL_ARM_EDB7XXX
409
 

powered by: WebSVN 2.1.0

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