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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      loop_serial.c
4
//
5
//      Loopback serial device driver
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):   nickg
43
// Contributors: nickg
44
// Date:        1999-02-25
45
// Purpose:     Loopback serial device driver
46
// Description: This device driver implements a pair of serial lines that are
47
//              connected back-to-back. Data output to one will appear as
48
//              input on the other. This process in in part driven by an alarm
49
//              object which provides a degree of separation between the two
50
//              channels.
51
//
52
//####DESCRIPTIONEND####
53
//
54
//==========================================================================
55
 
56
#include <pkgconf/hal.h>
57
#include <pkgconf/io_serial.h>
58
#include <pkgconf/io_serial_loop.h>
59
#include <cyg/hal/hal_io.h>
60
 
61
#include <cyg/io/io.h>
62
#include <cyg/io/devtab.h>
63
#include <cyg/io/serial.h>
64
#include <cyg/hal/hal_intr.h>
65
#include <cyg/kernel/kapi.h>
66
 
67
#ifdef CYGPKG_IO_SERIAL_LOOP
68
 
69
//-------------------------------------------------------------------------
70
 
71
extern void diag_printf(const char *fmt, ...);
72
 
73
//-------------------------------------------------------------------------
74
// Forward definitions
75
 
76
static bool loop_serial_init(struct cyg_devtab_entry *tab);
77
static bool loop_serial_putc(serial_channel *chan, unsigned char c);
78
static Cyg_ErrNo loop_serial_lookup(struct cyg_devtab_entry **tab,
79
                                   struct cyg_devtab_entry *sub_tab,
80
                                   const char *name);
81
static unsigned char loop_serial_getc(serial_channel *chan);
82
static Cyg_ErrNo loop_serial_set_config(serial_channel *chan, cyg_uint32 key,
83
                                        const void *xbuf, cyg_uint32 *len);
84
static void loop_serial_start_xmit(serial_channel *chan);
85
static void loop_serial_stop_xmit(serial_channel *chan);
86
 
87
#ifndef CYGPKG_IO_SERIAL_LOOP_POLLED_MODE
88
static void alarm_handler(cyg_handle_t alarm, cyg_addrword_t data);
89
#endif
90
 
91
//-------------------------------------------------------------------------
92
// Alarm object for feeding data back into serial channels
93
 
94
static cyg_alarm alarm_obj;
95
 
96
static cyg_handle_t alarm_handle;
97
 
98
//-------------------------------------------------------------------------
99
// Transfer FIFOs
100
 
101
#define FIFO_SIZE 16
102
 
103
struct fifo
104
{
105
    cyg_bool            tx_enable;
106
    volatile int        head;
107
    volatile int        tail;
108
    volatile int        num;
109
    volatile char       buf[FIFO_SIZE+1];
110
};
111
 
112
static struct fifo fifo0 = { false, 0, 0, 0 };   // from serial0 to serial1
113
static struct fifo fifo1 = { false, 0, 0, 0 };   // from serial1 to serial0
114
 
115
//-------------------------------------------------------------------------
116
 
117
#define BUFSIZE 128
118
 
119
//-------------------------------------------------------------------------
120
// Info for each serial device controlled
121
 
122
typedef struct loop_serial_info {
123
    struct fifo         *write_fifo;
124
    struct fifo         *read_fifo;
125
} loop_serial_info;
126
 
127
//-------------------------------------------------------------------------
128
// Callback functions exported by this driver
129
 
130
static SERIAL_FUNS(loop_serial_funs,
131
                   loop_serial_putc,
132
                   loop_serial_getc,
133
                   loop_serial_set_config,
134
                   loop_serial_start_xmit,
135
                   loop_serial_stop_xmit
136
    );
137
 
138
//-------------------------------------------------------------------------
139
// Hardware info for each serial line
140
 
141
#ifdef CYGPKG_IO_SERIAL_LOOP_SERIAL0
142
static loop_serial_info loop_serial_info0 = {
143
    &fifo0,
144
    &fifo1
145
};
146
#if CYGNUM_IO_SERIAL_LOOP_SERIAL0_BUFSIZE > 0
147
static unsigned char loop_serial_out_buf0[CYGNUM_IO_SERIAL_LOOP_SERIAL0_BUFSIZE];
148
static unsigned char loop_serial_in_buf0[CYGNUM_IO_SERIAL_LOOP_SERIAL0_BUFSIZE];
149
#endif
150
#endif // CYGPKG_IO_SERIAL_LOOP_SERIAL0
151
 
152
#ifdef CYGPKG_IO_SERIAL_LOOP_SERIAL1
153
static loop_serial_info loop_serial_info1 = {
154
    &fifo1,
155
    &fifo0
156
};
157
#if CYGNUM_IO_SERIAL_LOOP_SERIAL1_BUFSIZE > 0
158
static unsigned char loop_serial_out_buf1[CYGNUM_IO_SERIAL_LOOP_SERIAL1_BUFSIZE];
159
static unsigned char loop_serial_in_buf1[CYGNUM_IO_SERIAL_LOOP_SERIAL1_BUFSIZE];
160
#endif
161
#endif // CYGPKG_IO_SERIAL_LOOP_SERIAL1
162
 
163
//-------------------------------------------------------------------------
164
// Channel descriptions:
165
 
166
#ifdef CYGPKG_IO_SERIAL_LOOP_POLLED_MODE
167
#define SIZEOF_BUF(_x_) 0
168
#else
169
#define SIZEOF_BUF(_x_) sizeof(_x_)
170
#endif
171
 
172
#ifdef CYGPKG_IO_SERIAL_LOOP_SERIAL0
173
#if CYGNUM_IO_SERIAL_LOOP_SERIAL0_BUFSIZE > 0
174
static SERIAL_CHANNEL_USING_INTERRUPTS(loop_serial_channel0,
175
                                       loop_serial_funs,
176
                                       loop_serial_info0,
177
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_LOOP_SERIAL0_BAUD),
178
                                       CYG_SERIAL_STOP_DEFAULT,
179
                                       CYG_SERIAL_PARITY_DEFAULT,
180
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
181
                                       CYG_SERIAL_FLAGS_DEFAULT,
182
                                       &loop_serial_out_buf0[0],
183
                                       SIZEOF_BUF(loop_serial_out_buf0),
184
                                       &loop_serial_in_buf0[0],
185
                                       SIZEOF_BUF(loop_serial_in_buf0)
186
    );
187
#else
188
static SERIAL_CHANNEL(loop_serial_channel0,
189
                      loop_serial_funs,
190
                      loop_serial_info0,
191
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_LOOP_SERIAL0_BAUD),
192
                      CYG_SERIAL_STOP_DEFAULT,
193
                      CYG_SERIAL_PARITY_DEFAULT,
194
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
195
                      CYG_SERIAL_FLAGS_DEFAULT
196
    );
197
#endif
198
#endif // CYGPKG_IO_SERIAL_LOOP_SERIAL0
199
 
200
#ifdef CYGPKG_IO_SERIAL_LOOP_SERIAL1
201
#if CYGNUM_IO_SERIAL_LOOP_SERIAL1_BUFSIZE > 0
202
static SERIAL_CHANNEL_USING_INTERRUPTS(loop_serial_channel1,
203
                                       loop_serial_funs,
204
                                       loop_serial_info1,
205
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_LOOP_SERIAL1_BAUD),
206
                                       CYG_SERIAL_STOP_DEFAULT,
207
                                       CYG_SERIAL_PARITY_DEFAULT,
208
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
209
                                       CYG_SERIAL_FLAGS_DEFAULT,
210
                                       &loop_serial_out_buf1[0],
211
                                       SIZEOF_BUF(loop_serial_out_buf1),
212
                                       &loop_serial_in_buf1[0],
213
                                       SIZEOF_BUF(loop_serial_in_buf1)
214
    );
215
#else
216
static SERIAL_CHANNEL(loop_serial_channel1,
217
                      loop_serial_funs,
218
                      loop_serial_info1,
219
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_LOOP_SERIAL1_BAUD),
220
                      CYG_SERIAL_STOP_DEFAULT,
221
                      CYG_SERIAL_PARITY_DEFAULT,
222
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
223
                      CYG_SERIAL_FLAGS_DEFAULT
224
    );
225
#endif
226
#endif // CYGPKG_IO_SERIAL_LOOP_SERIAL1
227
 
228
//-------------------------------------------------------------------------
229
// And finally, the device table entries:
230
 
231
#ifdef CYGPKG_IO_SERIAL_LOOP_SERIAL0
232
DEVTAB_ENTRY(loop_serial_io0,
233
             CYGDAT_IO_SERIAL_LOOP_SERIAL0_NAME,
234
             0,                     // Does not depend on a lower level interface
235
             &cyg_io_serial_devio,
236
             loop_serial_init,
237
             loop_serial_lookup,     // Serial driver may need initializing
238
             &loop_serial_channel0
239
    );
240
#endif // CYGPKG_IO_SERIAL_LOOP_SERIAL0
241
 
242
#ifdef CYGPKG_IO_SERIAL_LOOP_SERIAL1
243
DEVTAB_ENTRY(loop_serial_io1,
244
             CYGDAT_IO_SERIAL_LOOP_SERIAL1_NAME,
245
             0,                     // Does not depend on a lower level interface
246
             &cyg_io_serial_devio,
247
             loop_serial_init,
248
             loop_serial_lookup,     // Serial driver may need initializing
249
             &loop_serial_channel1
250
    );
251
#endif // CYGPKG_IO_SERIAL_LOOP_SERIAL1
252
 
253
//-------------------------------------------------------------------------
254
 
255
static bool
256
loop_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
257
{
258
//    loop_serial_info *loop_chan = (loop_serial_info *)chan->dev_priv;
259
 
260
    if (new_config != &chan->config) {
261
        chan->config = *new_config;
262
    }
263
    return true;
264
}
265
 
266
//-------------------------------------------------------------------------
267
// Function to initialize the device.  Called at bootstrap time.
268
 
269
bool loop_serial_init(struct cyg_devtab_entry *tab)
270
{
271
    serial_channel *chan = (serial_channel *)tab->priv;
272
//    loop_serial_info *loop_chan = (loop_serial_info *)chan->dev_priv;
273
 
274
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
275
 
276
#ifndef CYGPKG_IO_SERIAL_LOOP_POLLED_MODE    
277
 
278
    // Set up alarm for feeding data back into channels
279
 
280
    cyg_alarm_create( cyg_real_time_clock(),
281
                      alarm_handler,
282
                      0,
283
                      &alarm_handle,
284
                      &alarm_obj);
285
 
286
    cyg_alarm_initialize( alarm_handle, 1, 1 );
287
 
288
#endif
289
 
290
    loop_serial_config_port(chan, &chan->config, true);
291
 
292
    return true;
293
}
294
 
295
//-------------------------------------------------------------------------
296
// This routine is called when the device is "looked" up (i.e. attached)
297
 
298
static Cyg_ErrNo
299
loop_serial_lookup(struct cyg_devtab_entry **tab,
300
                  struct cyg_devtab_entry *sub_tab,
301
                  const char *name)
302
{
303
    serial_channel *chan = (serial_channel *)(*tab)->priv;
304
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
305
    return ENOERR;
306
}
307
 
308
//-------------------------------------------------------------------------
309
// Return 'true' if character is sent to device
310
 
311
bool
312
loop_serial_putc(serial_channel *chan, unsigned char c)
313
{
314
    loop_serial_info *loop_chan = (loop_serial_info *)chan->dev_priv;
315
 
316
    struct fifo *f = loop_chan->write_fifo;
317
 
318
    if( f->num == FIFO_SIZE )
319
        return false;
320
 
321
    f->buf[f->tail] = c;
322
    f->num++;
323
    f->tail++;
324
    if( f->tail == sizeof(f->buf) )
325
        f->tail = 0;
326
 
327
    return true;
328
}
329
 
330
//-------------------------------------------------------------------------
331
 
332
unsigned char
333
loop_serial_getc(serial_channel *chan)
334
{
335
    unsigned char c;
336
    loop_serial_info *loop_chan = (loop_serial_info *)chan->dev_priv;
337
 
338
    struct fifo *f = loop_chan->read_fifo;
339
 
340
    while( f->num == 0 )
341
        continue;
342
 
343
    c = f->buf[f->head];
344
    f->num--;
345
    f->head++;
346
    if( f->head == sizeof(f->buf) )
347
        f->head = 0;
348
 
349
    return c;
350
}
351
 
352
//-------------------------------------------------------------------------
353
 
354
static Cyg_ErrNo
355
loop_serial_set_config(serial_channel *chan, cyg_uint32 key,
356
                       const void *xbuf, cyg_uint32 *len)
357
{
358
    switch (key) {
359
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
360
      {
361
        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
362
        if ( *len < sizeof(cyg_serial_info_t) ) {
363
            return -EINVAL;
364
        }
365
        *len = sizeof(cyg_serial_info_t);
366
        if ( true != loop_serial_config_port(chan, config, false) )
367
            return -EINVAL;
368
      }
369
      break;
370
    default:
371
        return -EINVAL;
372
    }
373
    return ENOERR;
374
}
375
 
376
//-------------------------------------------------------------------------
377
// Enable the transmitter on the device
378
 
379
static void
380
loop_serial_start_xmit(serial_channel *chan)
381
{
382
#ifndef CYGPKG_IO_SERIAL_LOOP_POLLED_MODE    
383
    loop_serial_info *loop_chan = (loop_serial_info *)chan->dev_priv;
384
 
385
    loop_chan->write_fifo->tx_enable = true;
386
 
387
    (chan->callbacks->xmt_char)(chan);
388
#endif    
389
}
390
 
391
//-------------------------------------------------------------------------
392
// Disable the transmitter on the device
393
 
394
static void
395
loop_serial_stop_xmit(serial_channel *chan)
396
{
397
#ifndef CYGPKG_IO_SERIAL_LOOP_POLLED_MODE    
398
    loop_serial_info *loop_chan = (loop_serial_info *)chan->dev_priv;
399
 
400
    loop_chan->write_fifo->tx_enable = false;
401
 
402
#endif    
403
}
404
 
405
//-------------------------------------------------------------------------
406
 
407
static void alarm_handler(cyg_handle_t alarm, cyg_addrword_t data)
408
{
409
    serial_channel *chan0 = &loop_serial_channel0;
410
    serial_channel *chan1 = &loop_serial_channel1;
411
 
412
    while( fifo0.num )
413
    {
414
        // Data ready for delivery to serial1
415
 
416
        struct fifo *f = &fifo0;
417
        char c;
418
 
419
        c = f->buf[f->head];
420
        f->num--;
421
        f->head++;
422
        if( f->head == sizeof(f->buf) )
423
            f->head = 0;
424
 
425
        (chan1->callbacks->rcv_char)(chan1, c);
426
        if( f->tx_enable )
427
            (chan0->callbacks->xmt_char)(chan0);
428
    }
429
 
430
    while( fifo1.num )
431
    {
432
        // Data ready for delivery to serial0
433
 
434
        struct fifo *f = &fifo1;
435
        char c;
436
 
437
        c = f->buf[f->head];
438
        f->num--;
439
        f->head++;
440
        if( f->head == sizeof(f->buf) )
441
            f->head = 0;
442
 
443
        (chan0->callbacks->rcv_char)(chan0, c);
444
        if( f->tx_enable )
445
            (chan1->callbacks->xmt_char)(chan1);
446
    }
447
 
448
 
449
 
450
}
451
 
452
 
453
#endif // CYGPKG_IO_SERIAL_LOOP
454
 
455
//-------------------------------------------------------------------------
456
// EOF loop.c

powered by: WebSVN 2.1.0

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