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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [serial/] [generic/] [16x5x/] [current/] [src/] [ser_16x5x.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      io/serial/generic/16x5x/ser_16x5x.c
4
//
5
//      Generic 16x5x serial 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, 2003, 2006 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, jlarmour, jskov
44
// Date:         1999-02-04
45
// Purpose:      16x5x generic serial driver
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
 
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
#include <cyg/infra/cyg_ass.h>
62
#include <cyg/hal/hal_io.h>
63
 
64
// Only compile driver if an inline file with driver details was selected.
65
#ifdef CYGDAT_IO_SERIAL_GENERIC_16X5X_INL
66
 
67
#ifndef CYGPRI_IO_SERIAL_GENERIC_16X5X_STEP
68
#define CYGPRI_IO_SERIAL_GENERIC_16X5X_STEP 1
69
#endif
70
 
71
#define SER_REG(_x_) ((_x_)*CYGPRI_IO_SERIAL_GENERIC_16X5X_STEP)
72
 
73
// Receive control Registers
74
#define REG_rhr SER_REG(0)    // Receive holding register
75
#define REG_isr SER_REG(2)    // Interrupt status register
76
#define REG_lsr SER_REG(5)    // Line status register
77
#define REG_msr SER_REG(6)    // Modem status register
78
#define REG_scr SER_REG(7)    // Scratch register
79
 
80
// Transmit control Registers
81
#define REG_thr SER_REG(0)    // Transmit holding register
82
#define REG_ier SER_REG(1)    // Interrupt enable register
83
#define REG_fcr SER_REG(2)    // FIFO control register
84
#define REG_lcr SER_REG(3)    // Line control register
85
#define REG_mcr SER_REG(4)    // Modem control register
86
#define REG_ldl SER_REG(0)    // LSB of baud rate
87
#define REG_mdl SER_REG(1)    // MSB of baud rate
88
 
89
// Interrupt Enable Register
90
#define IER_RCV 0x01
91
#define IER_XMT 0x02
92
#define IER_LS  0x04
93
#define IER_MS  0x08
94
 
95
// Line Control Register
96
#define LCR_WL5 0x00    // Word length
97
#define LCR_WL6 0x01
98
#define LCR_WL7 0x02
99
#define LCR_WL8 0x03
100
#define LCR_SB1 0x00    // Number of stop bits
101
#define LCR_SB1_5 0x04  // 1.5 -> only valid with 5 bit words
102
#define LCR_SB2 0x04
103
#define LCR_PN  0x00    // Parity mode - none
104
#define LCR_PE  0x18    // Parity mode - even
105
#define LCR_PO  0x08    // Parity mode - odd
106
#define LCR_PM  0x28    // Forced "mark" parity
107
#define LCR_PS  0x38    // Forced "space" parity
108
#define LCR_DL  0x80    // Enable baud rate latch
109
 
110
// Line Status Register
111
#define LSR_RSR 0x01
112
#define LSR_OE  0x02
113
#define LSR_PE  0x04
114
#define LSR_FE  0x08
115
#define LSR_BI  0x10
116
#define LSR_THE 0x20
117
#define LSR_TEMT 0x40
118
#define LSR_FIE 0x80
119
 
120
// Modem Control Register
121
#define MCR_DTR  0x01
122
#define MCR_RTS  0x02
123
#define MCR_INT  0x08   // Enable interrupts
124
#define MCR_LOOP 0x10   // Loopback mode
125
 
126
// Interrupt status Register
127
#define ISR_MS        0x00
128
#define ISR_nIP       0x01
129
#define ISR_Tx        0x02
130
#define ISR_Rx        0x04
131
#define ISR_LS        0x06
132
#define ISR_RxTO      0x0C
133
#define ISR_64BFIFO   0x20
134
#define ISR_FIFOworks 0x40
135
#define ISR_FIFOen    0x80
136
 
137
// Modem Status Register
138
#define MSR_DCTS 0x01
139
#define MSR_DDSR 0x02
140
#define MSR_TERI 0x04
141
#define MSR_DDCD 0x08
142
#define MSR_CTS  0x10
143
#define MSR_DSR  0x20
144
#define MSR_RI   0x40
145
#define MSR_CD   0x80
146
 
147
// FIFO Control Register
148
#define FCR_FE   0x01    // FIFO enable
149
#define FCR_CRF  0x02    // Clear receive FIFO
150
#define FCR_CTF  0x04    // Clear transmit FIFO
151
#define FCR_DMA  0x08    // DMA mode select
152
#define FCR_F64  0x20    // Enable 64 byte fifo (16750+)
153
#define FCR_RT14 0xC0    // Set Rx trigger at 14
154
#define FCR_RT8  0x80    // Set Rx trigger at 8
155
#define FCR_RT4  0x40    // Set Rx trigger at 4
156
#define FCR_RT1  0x00    // Set Rx trigger at 1
157
 
158
static unsigned char select_word_length[] = {
159
    LCR_WL5,    // 5 bits / word (char)
160
    LCR_WL6,
161
    LCR_WL7,
162
    LCR_WL8
163
};
164
 
165
static unsigned char select_stop_bits[] = {
166
    0,
167
    LCR_SB1,    // 1 stop bit
168
    LCR_SB1_5,  // 1.5 stop bit
169
    LCR_SB2     // 2 stop bits
170
};
171
 
172
static unsigned char select_parity[] = {
173
    LCR_PN,     // No parity
174
    LCR_PE,     // Even parity
175
    LCR_PO,     // Odd parity
176
    LCR_PM,     // Mark parity
177
    LCR_PS,     // Space parity
178
};
179
 
180
// selec_baud[] must be define by the client
181
 
182
typedef struct pc_serial_info {
183
    cyg_addrword_t base;
184
    int            int_num;
185
#ifdef CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
186
    int            int_prio;
187
#endif // CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
188
    cyg_interrupt  serial_interrupt;
189
    cyg_handle_t   serial_interrupt_handle;
190
#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
191
    enum {
192
        sNone = 0,
193
        s8250,
194
        s16450,
195
        s16550,
196
        s16550a
197
    } deviceType;
198
    unsigned tx_fifo_size;
199
    volatile unsigned tx_fifo_avail;
200
#endif
201
} pc_serial_info;
202
 
203
static bool pc_serial_init(struct cyg_devtab_entry *tab);
204
static bool pc_serial_putc(serial_channel *chan, unsigned char c);
205
static Cyg_ErrNo pc_serial_lookup(struct cyg_devtab_entry **tab,
206
                                  struct cyg_devtab_entry *sub_tab,
207
                                  const char *name);
208
static unsigned char pc_serial_getc(serial_channel *chan);
209
static Cyg_ErrNo pc_serial_set_config(serial_channel *chan, cyg_uint32 key,
210
                                      const void *xbuf, cyg_uint32 *len);
211
static void pc_serial_start_xmit(serial_channel *chan);
212
static void pc_serial_stop_xmit(serial_channel *chan);
213
 
214
static cyg_uint32 pc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
215
static void       pc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count,
216
                                cyg_addrword_t data);
217
 
218
static SERIAL_FUNS(pc_serial_funs,
219
                   pc_serial_putc,
220
                   pc_serial_getc,
221
                   pc_serial_set_config,
222
                   pc_serial_start_xmit,
223
                   pc_serial_stop_xmit
224
    );
225
 
226
#include CYGDAT_IO_SERIAL_GENERIC_16X5X_INL
227
 
228
#ifndef CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY
229
# define CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY 4
230
#endif
231
 
232
// Allow platform code to override the default implementation of
233
// a write to the LCR
234
#ifndef SER_16X5X_WRITE_LCR
235
#define SER_16X5X_WRITE_LCR(_base_, _val_) HAL_WRITE_UINT8((_base_) + REG_lcr, _val_)
236
#endif
237
 
238
// Allow platform code to override the default implementation of
239
// a read of the ISR
240
#ifndef SER_16X5X_READ_ISR
241
#define SER_16X5X_READ_ISR(_base_, _val_) HAL_READ_UINT8((_base_) + REG_isr, _val_)
242
#endif
243
 
244
// Internal function to actually configure the hardware to desired
245
// baud rate, etc.
246
static bool
247
serial_config_port(serial_channel *chan,
248
                   cyg_serial_info_t *new_config, bool init)
249
{
250
    pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
251
    cyg_addrword_t base = ser_chan->base;
252
    //
253
    // If the device supports a dynamic per channel baudrate generator
254
    // then we call the CYG_IO_SERIAL_GENERIC_16X5X_CHAN_BAUD_GENERATOR() 
255
    // macro to get the baud divisor. The macro takes the serial channel data 
256
    // pointer and the baudrate as parameters and returns the baud divisior
257
    //
258
#ifdef CYG_IO_SERIAL_GENERIC_16X5X_CHAN_BAUD_GENERATOR
259
    unsigned short baud_divisor = CYG_IO_SERIAL_GENERIC_16X5X_CHAN_BAUD_GENERATOR(ser_chan, new_config->baud);
260
#else
261
    unsigned short baud_divisor = select_baud[new_config->baud];
262
#endif
263
    unsigned char _lcr, _ier;
264
    if (baud_divisor == 0) return false;  // Invalid configuration
265
 
266
    // Disable port interrupts while changing hardware
267
    HAL_READ_UINT8(base+REG_ier, _ier);
268
    HAL_WRITE_UINT8(base+REG_ier, 0);
269
 
270
    _lcr = select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
271
        select_stop_bits[new_config->stop] |
272
        select_parity[new_config->parity];
273
    SER_16X5X_WRITE_LCR(base, _lcr | LCR_DL);
274
    HAL_WRITE_UINT8(base+REG_mdl, baud_divisor >> 8);
275
    HAL_WRITE_UINT8(base+REG_ldl, baud_divisor & 0xFF);
276
    SER_16X5X_WRITE_LCR(base, _lcr);
277
    if (init) {
278
#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
279
        unsigned char _fcr_thresh;
280
        cyg_uint8 b;
281
 
282
        /* First, find out what kind of device it is. */
283
        ser_chan->deviceType = sNone;
284
        HAL_WRITE_UINT8(base+REG_mcr, MCR_LOOP); // enable loopback mode
285
        HAL_READ_UINT8(base+REG_msr, b);
286
        if (0 == (b & 0xF0)) {   // see if MSR had CD, RI, DSR or CTS set
287
            HAL_WRITE_UINT8(base+REG_mcr, MCR_LOOP|MCR_DTR|MCR_RTS);
288
            HAL_READ_UINT8(base+REG_msr, b);
289
            if (0xF0 != (b & 0xF0))  // check that all of CD,RI,DSR and CTS set
290
                ser_chan->deviceType = s8250;
291
        }
292
        HAL_WRITE_UINT8(base+REG_mcr, 0); // disable loopback mode
293
 
294
        if (ser_chan->deviceType == s8250) {
295
            // Check for a scratch register; scratch register 
296
            // indicates 16450 or above.
297
            HAL_WRITE_UINT8(base+REG_scr, 0x55);
298
            HAL_READ_UINT8(base+REG_scr, b);
299
            if (b == 0x55) {
300
                HAL_WRITE_UINT8(base+REG_scr, 0xAA);
301
                HAL_READ_UINT8(base+REG_scr, b);
302
                if (b == 0xAA)
303
                    ser_chan->deviceType = s16450;
304
            }
305
        }
306
 
307
        if (ser_chan->deviceType == s16450) {
308
            // Check for a FIFO
309
            HAL_WRITE_UINT8(base+REG_fcr, FCR_FE);
310
            HAL_READ_UINT8(base+REG_isr, b);
311
            if (b & ISR_FIFOen)
312
                ser_chan->deviceType = s16550; // but FIFO doesn't 
313
                                               // necessarily work
314
            if (b & ISR_FIFOworks)
315
                ser_chan->deviceType = s16550a; // 16550a FIFOs work
316
        }
317
 
318
        if (ser_chan->deviceType == s16550a) {
319
            switch(CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO_RX_THRESHOLD) {
320
            default:
321
            case 1:
322
                _fcr_thresh=FCR_RT1; break;
323
            case 4:
324
                _fcr_thresh=FCR_RT4; break;
325
            case 8:
326
                _fcr_thresh=FCR_RT8; break;
327
            case 14:
328
                _fcr_thresh=FCR_RT14; break;
329
            }
330
            _fcr_thresh|=FCR_FE|FCR_CRF|FCR_CTF;
331
            ser_chan->tx_fifo_size =
332
              CYGNUM_IO_SERIAL_GENERIC_16X5X_FIFO_TX_SIZE;
333
            // Enable and clear FIFO
334
            HAL_WRITE_UINT8(base+REG_fcr, _fcr_thresh);
335
        }
336
        else {
337
            ser_chan->tx_fifo_size = 1;
338
            HAL_WRITE_UINT8(base+REG_fcr, 0); // make sure it's disabled
339
        }
340
 
341
        ser_chan->tx_fifo_avail = ser_chan->tx_fifo_size;
342
#endif
343
        if (chan->out_cbuf.len != 0) {
344
            _ier = IER_RCV;
345
        } else {
346
            _ier = 0;
347
        }
348
        // Master interrupt enable
349
        HAL_WRITE_UINT8(base+REG_mcr, MCR_INT|MCR_DTR|MCR_RTS);
350
    }
351
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
352
    _ier |= (IER_LS|IER_MS);
353
#endif
354
    HAL_WRITE_UINT8(base+REG_ier, _ier);
355
 
356
#ifdef CYGPRI_IO_SERIAL_GENERIC_16X5X_PLF_INIT_HOOK
357
    CYGPRI_IO_SERIAL_GENERIC_16X5X_PLF_INIT_HOOK( ser_chan, new_config );
358
#endif
359
 
360
    if (new_config != &chan->config) {
361
        chan->config = *new_config;
362
    }
363
    return true;
364
}
365
 
366
// Function to initialize the device.  Called at bootstrap time.
367
static bool
368
pc_serial_init(struct cyg_devtab_entry *tab)
369
{
370
    serial_channel *chan = (serial_channel *)tab->priv;
371
    pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
372
 
373
#ifdef CYG_IO_SERIAL_GENERIC_16X5X_BAUD_GENERATOR
374
    // Fill in baud rate table - used for platforms where this cannot
375
    // be determined statically
376
    int baud_idx, baud_val;
377
    if (select_baud[0] == 9999) {
378
        // Table not yet initialized
379
        // Assumes that 'select_baud' looks like this:
380
        //   static int select_baud[] = {
381
        //       9999,  -- marker
382
        //       50,    -- first baud rate
383
        //       110,   -- second baud rate
384
        // etc.
385
        for (baud_idx = 1;  baud_idx < sizeof(select_baud)/sizeof(select_baud[0]);  baud_idx++) {
386
            baud_val = CYG_IO_SERIAL_GENERIC_16X5X_BAUD_GENERATOR(select_baud[baud_idx]);
387
            select_baud[baud_idx] = baud_val;
388
        }
389
        select_baud[0] = 0;
390
    }
391
#endif
392
 
393
#ifdef CYGDBG_IO_INIT
394
    diag_printf("16x5x SERIAL init - dev: %x.%d\n",
395
                ser_chan->base, ser_chan->int_num);
396
#endif
397
    // Really only required for interrupt driven devices
398
    (chan->callbacks->serial_init)(chan);
399
    //
400
    // If the device supports per channel interrupt priorities then
401
    // we take the priority from the serial channel data. If it does
402
    // not support per channel interrupt priority we fall back to
403
    // the old method and use CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY
404
    // to define the priority
405
    //
406
#ifdef CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
407
    cyg_priority_t intprio = ser_chan->int_prio;
408
#else 
409
    cyg_priority_t intprio = CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY;
410
#endif // CYGINT_IO_SERIAL_GENERIC_16X5X_CHAN_INTPRIO
411
    if (chan->out_cbuf.len != 0) {
412
        cyg_drv_interrupt_create(ser_chan->int_num,
413
                                 intprio,
414
                                 (cyg_addrword_t)chan,
415
                                 pc_serial_ISR,
416
                                 pc_serial_DSR,
417
                                 &ser_chan->serial_interrupt_handle,
418
                                 &ser_chan->serial_interrupt);
419
        cyg_drv_interrupt_attach(ser_chan->serial_interrupt_handle);
420
        cyg_drv_interrupt_unmask(ser_chan->int_num);
421
    }
422
    serial_config_port(chan, &chan->config, true);
423
    return true;
424
}
425
 
426
// This routine is called when the device is "looked" up (i.e. attached)
427
static Cyg_ErrNo
428
pc_serial_lookup(struct cyg_devtab_entry **tab,
429
                 struct cyg_devtab_entry *sub_tab,
430
                 const char *name)
431
{
432
    serial_channel *chan = (serial_channel *)(*tab)->priv;
433
 
434
    // Really only required for interrupt driven devices
435
    (chan->callbacks->serial_init)(chan);
436
    return ENOERR;
437
}
438
 
439
// Send a character to the device output buffer.
440
// Return 'true' if character is sent to device
441
static bool
442
pc_serial_putc(serial_channel *chan, unsigned char c)
443
{
444
#ifndef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
445
    cyg_uint8 _lsr;
446
#endif
447
    pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
448
    cyg_addrword_t base = ser_chan->base;
449
 
450
#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
451
    if (ser_chan->tx_fifo_avail > 0) {
452
        HAL_WRITE_UINT8(base+REG_thr, c);
453
        --ser_chan->tx_fifo_avail;
454
        return true;
455
    }
456
#else
457
    HAL_READ_UINT8(base+REG_lsr, _lsr);
458
    if (_lsr & LSR_THE) {
459
        // Transmit buffer is empty
460
        HAL_WRITE_UINT8(base+REG_thr, c);
461
        return true;
462
    }
463
#endif
464
    // No space
465
    return false;
466
}
467
 
468
// Fetch a character from the device input buffer, waiting if necessary
469
static unsigned char
470
pc_serial_getc(serial_channel *chan)
471
{
472
    unsigned char c;
473
    cyg_uint8 _lsr;
474
    pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
475
    cyg_addrword_t base = ser_chan->base;
476
 
477
    // Wait for char
478
    do {
479
        HAL_READ_UINT8(base+REG_lsr, _lsr);
480
    } while ((_lsr & LSR_RSR) == 0);
481
 
482
    HAL_READ_UINT8(base+REG_rhr, c);
483
    return c;
484
}
485
 
486
// Set up the device characteristics; baud rate, etc.
487
static Cyg_ErrNo
488
pc_serial_set_config(serial_channel *chan, cyg_uint32 key, const void *xbuf,
489
                     cyg_uint32 *len)
490
{
491
    switch (key) {
492
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
493
      {
494
        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
495
        if ( *len < sizeof(cyg_serial_info_t) ) {
496
            return -EINVAL;
497
        }
498
        *len = sizeof(cyg_serial_info_t);
499
        if ( true != serial_config_port(chan, config, false) )
500
            return -EINVAL;
501
      }
502
      break;
503
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
504
    case CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE:
505
      {
506
          cyg_uint8 _mcr;
507
          pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
508
          cyg_addrword_t base = ser_chan->base;
509
          cyg_uint32 *f = (cyg_uint32 *)xbuf;
510
          unsigned char mask=0;
511
          if ( *len < sizeof(*f) )
512
              return -EINVAL;
513
 
514
          if ( chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX )
515
              mask = MCR_RTS;
516
          if ( chan->config.flags & CYGNUM_SERIAL_FLOW_DSRDTR_RX )
517
              mask |= MCR_DTR;
518
          HAL_READ_UINT8(base+REG_mcr, _mcr);
519
          if (*f) // we should throttle
520
              _mcr &= ~mask;
521
          else // we should no longer throttle
522
              _mcr |= mask;
523
          HAL_WRITE_UINT8(base+REG_mcr, _mcr);
524
      }
525
      break;
526
    case CYG_IO_SET_CONFIG_SERIAL_HW_FLOW_CONFIG:
527
        // Nothing to do because we do support both RTSCTS and DSRDTR flow
528
        // control.
529
        // Other targets would clear any unsupported flags here and
530
        // would then return -ENOSUPP - the higher layer can then query
531
        // what flags are set and decide what to do. This is optimised for
532
        // the most common case - i.e. that authors know what their hardware
533
        // is capable of.
534
        // We just return ENOERR.
535
      break;
536
#endif
537
    default:
538
        return -EINVAL;
539
    }
540
    return ENOERR;
541
}
542
 
543
// Enable the transmitter on the device
544
static void
545
pc_serial_start_xmit(serial_channel *chan)
546
{
547
    pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
548
    cyg_addrword_t base = ser_chan->base;
549
    cyg_uint8 _ier;
550
 
551
    HAL_READ_UINT8(base+REG_ier, _ier);
552
    _ier |= IER_XMT;                    // Enable xmit interrupt
553
    HAL_WRITE_UINT8(base+REG_ier, _ier);
554
#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_XMIT_REQUIRE_PRIME
555
    (chan->callbacks->xmt_char)(chan);
556
#endif
557
}
558
 
559
// Disable the transmitter on the device
560
static void
561
pc_serial_stop_xmit(serial_channel *chan)
562
{
563
    pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
564
    cyg_addrword_t base = ser_chan->base;
565
    cyg_uint8 _ier;
566
 
567
    HAL_READ_UINT8(base+REG_ier, _ier);
568
    _ier &= ~IER_XMT;                   // Disable xmit interrupt
569
    HAL_WRITE_UINT8(base+REG_ier, _ier);
570
}
571
 
572
// Serial I/O - low level interrupt handler (ISR)
573
static cyg_uint32
574
pc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
575
{
576
    serial_channel *chan = (serial_channel *)data;
577
    pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
578
    cyg_drv_interrupt_mask(ser_chan->int_num);
579
    cyg_drv_interrupt_acknowledge(ser_chan->int_num);
580
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
581
}
582
 
583
// Serial I/O - high level interrupt handler (DSR)
584
static void
585
pc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
586
{
587
    serial_channel *chan = (serial_channel *)data;
588
    pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
589
    cyg_addrword_t base = ser_chan->base;
590
    cyg_uint8 _isr;
591
 
592
    // Check if we have an interrupt pending - note that the interrupt
593
    // is pending of the low bit of the isr is *0*, not 1.
594
    SER_16X5X_READ_ISR(base, _isr);
595
    while ((_isr & ISR_nIP) == 0) {
596
        switch (_isr&0xE) {
597
        case ISR_Rx:
598
        case ISR_RxTO:
599
        {
600
            cyg_uint8 _lsr;
601
            unsigned char c;
602
            HAL_READ_UINT8(base+REG_lsr, _lsr);
603
            while(_lsr & LSR_RSR) {
604
                HAL_READ_UINT8(base+REG_rhr, c);
605
                (chan->callbacks->rcv_char)(chan, c);
606
                HAL_READ_UINT8(base+REG_lsr, _lsr);
607
            }
608
            break;
609
        }
610
        case ISR_Tx:
611
#ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO
612
            ser_chan->tx_fifo_avail = ser_chan->tx_fifo_size;
613
#endif
614
            (chan->callbacks->xmt_char)(chan);
615
            break;
616
 
617
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
618
        case ISR_LS:
619
            {
620
                cyg_serial_line_status_t stat;
621
                cyg_uint8 _lsr;
622
                HAL_READ_UINT8(base+REG_lsr, _lsr);
623
 
624
                // this might look expensive, but it is rarely the case that
625
                // more than one of these is set
626
                stat.value = 1;
627
                if ( _lsr & LSR_OE ) {
628
                    stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;
629
                    (chan->callbacks->indicate_status)(chan, &stat );
630
                }
631
                if ( _lsr & LSR_PE ) {
632
                    stat.which = CYGNUM_SERIAL_STATUS_PARITYERR;
633
                    (chan->callbacks->indicate_status)(chan, &stat );
634
                }
635
                if ( _lsr & LSR_FE ) {
636
                    stat.which = CYGNUM_SERIAL_STATUS_FRAMEERR;
637
                    (chan->callbacks->indicate_status)(chan, &stat );
638
                }
639
                if ( _lsr & LSR_BI ) {
640
                    stat.which = CYGNUM_SERIAL_STATUS_BREAK;
641
                    (chan->callbacks->indicate_status)(chan, &stat );
642
                }
643
            }
644
            break;
645
 
646
        case ISR_MS:
647
            {
648
                cyg_serial_line_status_t stat;
649
                cyg_uint8 _msr;
650
 
651
                HAL_READ_UINT8(base+REG_msr, _msr);
652
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
653
                if ( _msr & MSR_DDSR )
654
                    if ( chan->config.flags & CYGNUM_SERIAL_FLOW_DSRDTR_TX ) {
655
                        stat.which = CYGNUM_SERIAL_STATUS_FLOW;
656
                        stat.value = (0 != (_msr & MSR_DSR));
657
                        (chan->callbacks->indicate_status)(chan, &stat );
658
                    }
659
                if ( _msr & MSR_DCTS )
660
                    if ( chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_TX ) {
661
                        stat.which = CYGNUM_SERIAL_STATUS_FLOW;
662
                        stat.value = (0 != (_msr & MSR_CTS));
663
                        (chan->callbacks->indicate_status)(chan, &stat );
664
                    }
665
#endif
666
                if ( _msr & MSR_DDCD ) {
667
                    stat.which = CYGNUM_SERIAL_STATUS_CARRIERDETECT;
668
                    stat.value = (0 != (_msr & MSR_CD));
669
                    (chan->callbacks->indicate_status)(chan, &stat );
670
                }
671
                if ( _msr & MSR_RI ) {
672
                    stat.which = CYGNUM_SERIAL_STATUS_RINGINDICATOR;
673
                    stat.value = 1;
674
                    (chan->callbacks->indicate_status)(chan, &stat );
675
                }
676
                if ( _msr & MSR_TERI ) {
677
                    stat.which = CYGNUM_SERIAL_STATUS_RINGINDICATOR;
678
                    stat.value = 0;
679
                    (chan->callbacks->indicate_status)(chan, &stat );
680
                }
681
            }
682
            break;
683
#endif
684
        default:
685
            // Yes, this assertion may well not be visible. *But*
686
            // if debugging, we may still successfully hit a breakpoint
687
            // on cyg_assert_fail, which _is_ useful
688
            CYG_FAIL("unhandled serial interrupt state");
689
        }
690
 
691
        HAL_READ_UINT8(base+REG_isr, _isr);
692
    } // while
693
 
694
    cyg_drv_interrupt_unmask(ser_chan->int_num);
695
}
696
#endif
697
 
698
// EOF ser_16x5x.c

powered by: WebSVN 2.1.0

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