tx3904_serial.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 758 行 · 第 1/2 页

C
758
字号
//==========================================================================
//
//      tx3904_serial.c
//
//      Serial device driver for TX3904 on-chip serial devices
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):   nickg
// Contributors: nickg
// Date:        1999-03-3
// Purpose:     TX3904 serial device driver
// Description: TX3904 serial device driver
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/hal.h>
#include <pkgconf/io_serial.h>
#include <cyg/hal/hal_io.h>
#include <cyg/hal/hal_intr.h>

#include <cyg/io/io.h>
#include <cyg/io/devtab.h>
#include <cyg/io/serial.h>

#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904

cyg_bool cyg_hal_is_break(char *buf, int size);
void cyg_hal_user_break( CYG_ADDRWORD *regs );

//-------------------------------------------------------------------------

extern void diag_printf(const char *fmt, ...);

//-------------------------------------------------------------------------
// Forward definitions

static bool tx3904_serial_init(struct cyg_devtab_entry *tab);
static bool tx3904_serial_putc(serial_channel *chan, unsigned char c);
static Cyg_ErrNo tx3904_serial_lookup(struct cyg_devtab_entry **tab, 
                                   struct cyg_devtab_entry *sub_tab,
                                   const char *name);
static unsigned char tx3904_serial_getc(serial_channel *chan);
static Cyg_ErrNo tx3904_serial_set_config(serial_channel *chan, cyg_uint32 key,
                                          const void *xbuf, cyg_uint32 *len);
static void tx3904_serial_start_xmit(serial_channel *chan);
static void tx3904_serial_stop_xmit(serial_channel *chan);

#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
static cyg_uint32 tx3904_serial_ISR(cyg_vector_t vector, cyg_addrword_t data, cyg_addrword_t *regs);
static void       tx3904_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
#endif


//-------------------------------------------------------------------------
// TX3904 serial line control register values:

// Offsets to serial control registers from base
#define SERIAL_CR       0x00
#define SERIAL_SR       0x04
#define SERIAL_ICR      0x08
#define SERIAL_ISR      0x0C
#define SERIAL_FCR      0x10
#define SERIAL_BRG      0x14
#define SERIAL_TXB      0x20
#define SERIAL_RXB      0x30

// Status register bits
#define ISR_RXRDY       0x01
#define ISR_TXRDY       0x02
#define ISR_ERROR       0x04

// Control register bits
#define LCR_SB1         0x0000
#define LCR_SB1_5       0x0000
#define LCR_SB2         0x0004
#define LCR_PN          0x0000    // Parity mode - none
#define LCR_PS          0x0000    // Forced "space" parity
#define LCR_PM          0x0000    // Forced "mark" parity
#define LCR_PE          0x0018    // Parity mode - even
#define LCR_PO          0x0010    // Parity mode - odd
#define LCR_WL5         0x0001    // not supported - use 7bit
#define LCR_WL6         0x0001    // not supported - use 7bit
#define LCR_WL7         0x0001    // 7 bit chars
#define LCR_WL8         0x0000    // 8 bit chars

#define LCR_BRG         0x0020    // Select baud rate generator

#define ICR_RXE         0x0001  // receive enable
#define ICR_TXE         0x0002  // transmit enable

//-------------------------------------------------------------------------
// Tables to map input values to hardware settings

static unsigned char select_word_length[] = {
    LCR_WL5,    // 5 bits / word (char)
    LCR_WL6,
    LCR_WL7,
    LCR_WL8
};

static unsigned char select_stop_bits[] = {
    0,
    LCR_SB1,    // 1 stop bit
    LCR_SB1_5,  // 1.5 stop bit
    LCR_SB2     // 2 stop bits
};

static unsigned char select_parity[] = {
    LCR_PN,     // No parity
    LCR_PE,     // Even parity
    LCR_PO,     // Odd parity
    LCR_PM,     // Mark parity
    LCR_PS,     // Space parity
};

// The values in this table plug straight into the BRG register
// in the serial driver hardware. They comprise a baud rate divisor
// in the bottom 8 bits and a clock selector in the top 8 bits.
// These figures all come from Toshiba.

#if (CYGHWR_HAL_MIPS_CPU_FREQ == 50)

static unsigned short select_baud[] = {
    0,          // Unused
    0,          // 50
    0,          // 75
    0,          // 110
    0,          // 134.5
    0,          // 150
    0,          // 200
    0,          // 300
    0x0300|20,  // 600
    0x0300|10,  // 1200
    0,          // 1800
    0x0300|05,  // 2400
    0,          // 3600
    0x0300|10,  // 4800
    0,          // 7200
    0x0200|05,  // 9600
    0,          // 14400
    0x0100|10,  // 19200
    0x0100|05,  // 38400
    0,          // 57600
    0,          // 115200
    0,          // 230400
};

#elif (CYGHWR_HAL_MIPS_CPU_FREQ == 66)

static unsigned short select_baud[] = {
    0,          // Unused
    0,          // 50
    0,          // 75
    0,          // 110
    0,          // 134.5
    0,          // 150
    0,          // 200
    0,          // 300
    0x0300|27,  // 600
    0x0200|54,  // 1200
    0,          // 1800
    0x0200|27,  // 2400
    0,          // 3600
    0x0100|54,  // 4800
    0,          // 7200
    0x0100|27,  // 9600
    0,          // 14400
    0x0000|54,  // 19200
    0x0000|27,  // 38400
    0,          // 57600
    0,          // 115200
    0,          // 230400
};

#else

#error Unsupported CPU frequency

#endif

//-------------------------------------------------------------------------
// Info for each serial device controlled

typedef struct tx3904_serial_info {
    CYG_ADDRWORD   base;
    CYG_WORD       int_num;
    cyg_interrupt  interrupt;
    cyg_handle_t   interrupt_handle;
    cyg_uint8      input_char;
    cyg_bool       input_char_valid;
    cyg_bool       output_ready;
    cyg_uint16     cur_baud;
} tx3904_serial_info;

//-------------------------------------------------------------------------
// Callback functions exported by this driver

static SERIAL_FUNS(tx3904_serial_funs, 
                   tx3904_serial_putc, 
                   tx3904_serial_getc,
                   tx3904_serial_set_config,
                   tx3904_serial_start_xmit,
                   tx3904_serial_stop_xmit
    );

//-------------------------------------------------------------------------
// Hardware info for each serial line

#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
static tx3904_serial_info tx3904_serial_info0 = {
    0xFFFFF300,
    CYGNUM_HAL_INTERRUPT_SIO_0
};
#if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE > 0
static unsigned char tx3904_serial_out_buf0[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE];
static unsigned char tx3904_serial_in_buf0[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE];
#endif
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0

#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
static tx3904_serial_info tx3904_serial_info1 = {
    0xFFFFF400,
    CYGNUM_HAL_INTERRUPT_SIO_1
};
#if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE > 0
static unsigned char tx3904_serial_out_buf1[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE];
static unsigned char tx3904_serial_in_buf1[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE];
#endif
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1

//-------------------------------------------------------------------------
// Channel descriptions:

#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
#define SIZEOF_BUF(_x_) 0
#else
#define SIZEOF_BUF(_x_) sizeof(_x_)
#endif

#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
#if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE > 0
static SERIAL_CHANNEL_USING_INTERRUPTS(tx3904_serial_channel0,
                                       tx3904_serial_funs, 
                                       tx3904_serial_info0,
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BAUD),
                                       CYG_SERIAL_STOP_DEFAULT,
                                       CYG_SERIAL_PARITY_DEFAULT,
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
                                       CYG_SERIAL_FLAGS_DEFAULT,
                                       &tx3904_serial_out_buf0[0],
                                       SIZEOF_BUF(tx3904_serial_out_buf0),
                                       &tx3904_serial_in_buf0[0],
                                       SIZEOF_BUF(tx3904_serial_in_buf0)
    );
#else
static SERIAL_CHANNEL(tx3904_serial_channel0,
                      tx3904_serial_funs, 
                      tx3904_serial_info0,
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BAUD),
                      CYG_SERIAL_STOP_DEFAULT,
                      CYG_SERIAL_PARITY_DEFAULT,
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
                      CYG_SERIAL_FLAGS_DEFAULT
    );
#endif
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0

#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
#if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE > 0
static SERIAL_CHANNEL_USING_INTERRUPTS(tx3904_serial_channel1,
                                       tx3904_serial_funs, 
                                       tx3904_serial_info1,
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BAUD),
                                       CYG_SERIAL_STOP_DEFAULT,
                                       CYG_SERIAL_PARITY_DEFAULT,
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
                                       CYG_SERIAL_FLAGS_DEFAULT,
                                       &tx3904_serial_out_buf1[0],
                                       SIZEOF_BUF(tx3904_serial_out_buf1),
                                       &tx3904_serial_in_buf1[0],
                                       SIZEOF_BUF(tx3904_serial_in_buf1)
    );
#else
static SERIAL_CHANNEL(tx3904_serial_channel1,
                      tx3904_serial_funs, 
                      tx3904_serial_info1,
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BAUD),
                      CYG_SERIAL_STOP_DEFAULT,
                      CYG_SERIAL_PARITY_DEFAULT,
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
                      CYG_SERIAL_FLAGS_DEFAULT
    );
#endif
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1

//-------------------------------------------------------------------------
// And finally, the device table entries:

#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
DEVTAB_ENTRY(tx3904_serial_io0, 
             CYGDAT_IO_SERIAL_TX39_JMR3904_SERIAL0_NAME,
             0,                     // Does not depend on a lower level interface
             &cyg_io_serial_devio, 
             tx3904_serial_init, 
             tx3904_serial_lookup,     // Serial driver may need initializing
             &tx3904_serial_channel0
    );
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0

#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
DEVTAB_ENTRY(tx3904_serial_io1, 
             CYGDAT_IO_SERIAL_TX39_JMR3904_SERIAL1_NAME,
             0,                     // Does not depend on a lower level interface
             &cyg_io_serial_devio, 
             tx3904_serial_init, 
             tx3904_serial_lookup,     // Serial driver may need initializing
             &tx3904_serial_channel1
    );
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1

// ------------------------------------------------------------------------
// Delay for some number of character times. This is based on the baud
// rate currently set. We use the numbers that plug in to the BRG
// clock select and divider to control two loops. The innermost delay
// loop uses a count that is derived from dividing the CPU frequency
// by the BRG granularity (and we then add 1 to compensate for any
// rounding).  This gives the number of cycles that the innermost loop
// must consume.  For the sake of simplicity we assume that this loop
// will take 1 cycle per loop, which is roughly true in optimized
// code.

void delay_char_time(tx3904_serial_info *tx3904_chan, int n)
{
    static cyg_uint16 clock_val[4] = { 4, 16, 64, 256 };
    cyg_uint16 baud_val = select_baud[tx3904_chan->cur_baud];
    cyg_count32 clock_loop = clock_val[baud_val>>8];
    cyg_count32 div_loop = baud_val & 0xFF;
    cyg_count32 bit_time = ((CYGHWR_HAL_MIPS_CPU_FREQ_ACTUAL)/(2457600)) + 1;
    
    n *= 11;    // allow for start and stop bits and 8 data bits
    
    while( n-- )

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?