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 + -
显示快捷键?