Mercurial > ecos-v2_0-branch
diff packages/devs/serial/sparclite/sleb/current/src/sleb_sdtr.c @ 82:6736c52df507 ecos-sw-2000-04-14
Merge from eCos master repository on 2000-04-14-13:35:46-BST
| author | jlarmour |
|---|---|
| date | Tue, 18 Apr 2000 21:51:55 +0000 |
| parents | |
| children | 6ed91473a1cd |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/devs/serial/sparclite/sleb/current/src/sleb_sdtr.c @@ -0,0 +1,375 @@ +//========================================================================== +// +// io/serial/sparclite/sleb_sdtr.c +// +// Serial I/O interface module for SPARClite Eval Board (SLEB) +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: gthomas +// Date: 1999-02-04 +// Purpose: SLEB serial I/O module +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/io.h> +#include <pkgconf/io_serial.h> +#include <cyg/io/io.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/io/devtab.h> +#include <cyg/io/serial.h> + +#ifdef CYGPKG_IO_SERIAL_SPARCLITE_SLEB + +#include "sleb_sdtr.h" + +extern void diag_printf(const char *fmt, ...); + +#define BUFSIZE 128 + +typedef struct sleb_sdtr_info { + CYG_ADDRWORD base; + CYG_WORD tx_int_num; + CYG_WORD rx_int_num; + cyg_interrupt tx_serial_interrupt; + cyg_handle_t tx_serial_interrupt_handle; + cyg_interrupt rx_serial_interrupt; + cyg_handle_t rx_serial_interrupt_handle; + cyg_uint8 cmd_reg; + bool xmit_enabled; +} sleb_sdtr_info; + +static bool sleb_sdtr_init(struct cyg_devtab_entry *tab); +static bool sleb_sdtr_putc(serial_channel *chan, unsigned char c); +static Cyg_ErrNo sleb_sdtr_lookup(struct cyg_devtab_entry **tab, + struct cyg_devtab_entry *sub_tab, + const char *name); +static unsigned char sleb_sdtr_getc(serial_channel *chan); +static bool sleb_sdtr_set_config(serial_channel *chan, cyg_serial_info_t *config); +static void sleb_sdtr_start_xmit(serial_channel *chan); +static void sleb_sdtr_stop_xmit(serial_channel *chan); + +static cyg_uint32 sleb_sdtr_tx_ISR(cyg_vector_t vector, cyg_addrword_t data); +static void sleb_sdtr_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data); +static cyg_uint32 sleb_sdtr_rx_ISR(cyg_vector_t vector, cyg_addrword_t data); +static void sleb_sdtr_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data); + +static SERIAL_FUNS(sleb_sdtr_funs, + sleb_sdtr_putc, + sleb_sdtr_getc, + sleb_sdtr_set_config, + sleb_sdtr_start_xmit, + sleb_sdtr_stop_xmit + ); + +#ifdef CYGPKG_IO_SERIAL_SPARCLITE_SLEB_CON1 +static sleb_sdtr_info sleb_sdtr_info0 = {SLEB_SDTR0_BASE, SLEB_SDTR0_TX_INT, SLEB_SDTR0_RX_INT}; +#if CYGNUM_IO_SERIAL_SPARCLITE_SLEB_CON1_BUFSIZE > 0 +static unsigned char sleb_sdtr_out_buf0[CYGNUM_IO_SERIAL_SPARCLITE_SLEB_CON1_BUFSIZE]; +static unsigned char sleb_sdtr_in_buf0[CYGNUM_IO_SERIAL_SPARCLITE_SLEB_CON1_BUFSIZE]; + +static SERIAL_CHANNEL_USING_INTERRUPTS(sleb_sdtr_channel0, + sleb_sdtr_funs, + sleb_sdtr_info0, + CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_SPARCLITE_SLEB_CON1_BAUD), + CYG_SERIAL_STOP_DEFAULT, + CYG_SERIAL_PARITY_DEFAULT, + CYG_SERIAL_WORD_LENGTH_DEFAULT, + CYG_SERIAL_FLAGS_DEFAULT, + &sleb_sdtr_out_buf0[0], sizeof(sleb_sdtr_out_buf0), + &sleb_sdtr_in_buf0[0], sizeof(sleb_sdtr_in_buf0) + ); +#else +static SERIAL_CHANNEL(sleb_sdtr_channel0, + sleb_sdtr_funs, + sleb_sdtr_info0, + CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_SPARCLITE_SLEB_CON1_BAUD), + CYG_SERIAL_STOP_DEFAULT, + CYG_SERIAL_PARITY_DEFAULT, + CYG_SERIAL_WORD_LENGTH_DEFAULT, + CYG_SERIAL_FLAGS_DEFAULT + ); +#endif + +DEVTAB_ENTRY(sleb_sdtr_io0, + CYGDAT_IO_SERIAL_SPARCLITE_SLEB_CON1_NAME, + 0, // Does not depend on a lower level interface + &cyg_io_serial_devio, + sleb_sdtr_init, + sleb_sdtr_lookup, // Serial driver may need initializing + &sleb_sdtr_channel0 + ); +#endif // CYGPKG_IO_SERIAL_SPARCLITE_SLEB_CON1 + +#ifdef CYGPKG_IO_SERIAL_SPARCLITE_SLEB_CON2 +static sleb_sdtr_info sleb_sdtr_info1 = {SLEB_SDTR1_BASE, SLEB_SDTR1_TX_INT, SLEB_SDTR1_RX_INT}; +#if CYGNUM_IO_SERIAL_SPARCLITE_SLEB_CON2_BUFSIZE > 0 +static unsigned char sleb_sdtr_out_buf1[CYGNUM_IO_SERIAL_SPARCLITE_SLEB_CON2_BUFSIZE]; +static unsigned char sleb_sdtr_in_buf1[CYGNUM_IO_SERIAL_SPARCLITE_SLEB_CON2_BUFSIZE]; + +static SERIAL_CHANNEL_USING_INTERRUPTS(sleb_sdtr_channel1, + sleb_sdtr_funs, + sleb_sdtr_info1, + CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_SPARCLITE_SLEB_CON2_BAUD), + CYG_SERIAL_STOP_DEFAULT, + CYG_SERIAL_PARITY_DEFAULT, + CYG_SERIAL_WORD_LENGTH_DEFAULT, + CYG_SERIAL_FLAGS_DEFAULT, + &sleb_sdtr_out_buf1[0], sizeof(sleb_sdtr_out_buf1), + &sleb_sdtr_in_buf1[0], sizeof(sleb_sdtr_in_buf1) + ); +#else +static SERIAL_CHANNEL(sleb_sdtr_channel1, + sleb_sdtr_funs, + sleb_sdtr_info1, + CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_SPARCLITE_SLEB_CON2_BAUD), + CYG_SERIAL_STOP_DEFAULT, + CYG_SERIAL_PARITY_DEFAULT, + CYG_SERIAL_WORD_LENGTH_DEFAULT, + CYG_SERIAL_FLAGS_DEFAULT + ); +#endif + +DEVTAB_ENTRY(sleb_sdtr_io1, + CYGDAT_IO_SERIAL_SPARCLITE_SLEB_CON2_NAME, + 0, // Does not depend on a lower level interface + &cyg_io_serial_devio, + sleb_sdtr_init, + sleb_sdtr_lookup, // Serial driver may need initializing + &sleb_sdtr_channel1 + ); +#endif // CYGPKG_IO_SERIAL_SPARCLITE_SLEB_CON2 + +// Internal function to actually configure the hardware to desired baud rate, etc. +static bool +sleb_sdtr_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init) +{ + sleb_sdtr_info *sdtr_chan = (sleb_sdtr_info *)chan->dev_priv; + CYG_ADDRWORD port = sdtr_chan->base; + cyg_int32 baud_divisor; + cyg_int32 clk, tval; + unsigned char mode; +#if 0 + if ((new_config->baud < CYGNUM_SERIAL_BAUD_MIN) || (new_config->baud > CYGNUM_SERIAL_BAUD_MAX)) + return false; // Invalid baud rate +#endif + baud_divisor = select_baud[new_config->baud]; + if (baud_divisor == 0) + return false; // Unsupported baud rate + // Reset the port + HAL_SPARC_86940_WRITE(SDTR_CONTROL(port), SDTR_CMD_RST); + // Write the mode + mode = SDTR_MODE_MODE_ASYNC16 | + select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] | + select_stop_bits[new_config->stop] | + select_parity[new_config->parity]; + HAL_SPARC_86940_WRITE(SDTR_CONTROL(port), mode); + // Set baud rate clock. + // ***** CAUTION! Both ports use the same time, thus they must both run at the same baud rate! + clk = *SLEB_CLOCK_SWITCH; // Compute board speed + if (clk & 0x80) clk = 10; + clk = (clk & 0x3F) * 1000000; // in MHz + tval = (clk / (baud_divisor * 32)) - 1; + HAL_SPARC_86940_WRITE(SLEB_TIMER3_RELOAD, tval); + // Set up control register + sdtr_chan->cmd_reg = SDTR_CMD_RTS | SDTR_CMD_DTR | SDTR_CMD_TxEN; +#ifdef CYGPKG_IO_SERIAL_SPARCLITE_SLEB_CON1 + // Cygmon needs the receiver + if ((chan->out_cbuf.len != 0) || (chan == &sleb_sdtr_channel0)) { +#else + if (chan->out_cbuf.len != 0) { +#endif + sdtr_chan->cmd_reg |= SDTR_CMD_RxEN; + } + if (init) { + sdtr_chan->xmit_enabled = false; + } + HAL_SPARC_86940_WRITE(SDTR_CONTROL(port), sdtr_chan->cmd_reg); + if (new_config != &chan->config) + chan->config = *new_config; + return true; +} + +// Function to initialize the device. Called at bootstrap time. +static bool +sleb_sdtr_init(struct cyg_devtab_entry *tab) +{ + serial_channel *chan = (serial_channel *)tab->priv; + sleb_sdtr_info *sdtr_chan = (sleb_sdtr_info *)chan->dev_priv; +#ifdef CYGDBG_IO_INIT + diag_printf("SLEB SERIAL init - dev: %x.%d.%d\n", sdtr_chan->base, sdtr_chan->tx_int_num, sdtr_chan->rx_int_num); +#endif + (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices + if (chan->out_cbuf.len != 0) { + cyg_drv_interrupt_create(sdtr_chan->tx_int_num, + 99, // Priority - unused + (cyg_addrword_t)chan, // Data item passed to interrupt handler + sleb_sdtr_tx_ISR, + sleb_sdtr_tx_DSR, + &sdtr_chan->tx_serial_interrupt_handle, + &sdtr_chan->tx_serial_interrupt); + cyg_drv_interrupt_attach(sdtr_chan->tx_serial_interrupt_handle); + cyg_drv_interrupt_mask(sdtr_chan->tx_int_num); + cyg_drv_interrupt_create(sdtr_chan->rx_int_num, + 99, // Priority - unused + (cyg_addrword_t)chan, // Data item passed to interrupt handler + sleb_sdtr_rx_ISR, + sleb_sdtr_rx_DSR, + &sdtr_chan->rx_serial_interrupt_handle, + &sdtr_chan->rx_serial_interrupt); + cyg_drv_interrupt_attach(sdtr_chan->rx_serial_interrupt_handle); + cyg_drv_interrupt_unmask(sdtr_chan->rx_int_num); + } + sleb_sdtr_config_port(chan, &chan->config, true); + return true; +} + +// This routine is called when the device is "looked" up (i.e. attached) +static Cyg_ErrNo +sleb_sdtr_lookup(struct cyg_devtab_entry **tab, + struct cyg_devtab_entry *sub_tab, + const char *name) +{ + serial_channel *chan = (serial_channel *)(*tab)->priv; + (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices + return ENOERR; +} + +// Send a character to the device output buffer. +// Return 'true' if character is sent to device +static bool +sleb_sdtr_putc(serial_channel *chan, unsigned char c) +{ + sleb_sdtr_info *sdtr_chan = (sleb_sdtr_info *)chan->dev_priv; + CYG_ADDRWORD port = sdtr_chan->base; + cyg_uint8 status; + HAL_SPARC_86940_READ(SDTR_STATUS(port), status); + if (status & SDTR_STAT_TxRDY) { +// Transmit buffer is empty + HAL_SPARC_86940_WRITE(SDTR_TXDATA(port), c); + return true; + } else { +// No space + return false; + } +} + +// Fetch a character from the device input buffer, waiting if necessary +static unsigned char +sleb_sdtr_getc(serial_channel *chan) +{ + unsigned char c; + sleb_sdtr_info *sdtr_chan = (sleb_sdtr_info *)chan->dev_priv; + CYG_ADDRWORD port = sdtr_chan->base; + cyg_uint8 status; + HAL_SPARC_86940_READ(SDTR_STATUS(port), status); + while ((status & SDTR_STAT_RxRDY) == 0) + HAL_SPARC_86940_READ(SDTR_STATUS(port), status); // Wait for char + HAL_SPARC_86940_READ(SDTR_RXDATA(port), c); + return c; +} + +// Set up the device characteristics; baud rate, etc. +static bool +sleb_sdtr_set_config(serial_channel *chan, cyg_serial_info_t *config) +{ + return sleb_sdtr_config_port(chan, config, false); +} + +// Enable the transmitter on the device +static void +sleb_sdtr_start_xmit(serial_channel *chan) +{ + sleb_sdtr_info *sdtr_chan = (sleb_sdtr_info *)chan->dev_priv; + sdtr_chan->xmit_enabled = true; + cyg_drv_interrupt_unmask(sdtr_chan->tx_int_num); +} + +// Disable the transmitter on the device +static void +sleb_sdtr_stop_xmit(serial_channel *chan) +{ + sleb_sdtr_info *sdtr_chan = (sleb_sdtr_info *)chan->dev_priv; + cyg_drv_interrupt_mask(sdtr_chan->tx_int_num); + sdtr_chan->xmit_enabled = false; +} + +// Serial I/O - low level interrupt handler (ISR) +static cyg_uint32 +sleb_sdtr_tx_ISR(cyg_vector_t vector, cyg_addrword_t data) +{ + serial_channel *chan = (serial_channel *)data; + sleb_sdtr_info *sdtr_chan = (sleb_sdtr_info *)chan->dev_priv; + cyg_drv_interrupt_mask(sdtr_chan->tx_int_num); + cyg_drv_interrupt_acknowledge(sdtr_chan->tx_int_num); + return CYG_ISR_CALL_DSR; // Cause DSR to be run +} + +// Serial I/O - high level interrupt handler (DSR) +static void +sleb_sdtr_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + serial_channel *chan = (serial_channel *)data; + sleb_sdtr_info *sdtr_chan = (sleb_sdtr_info *)chan->dev_priv; + (chan->callbacks->xmt_char)(chan); + if (sdtr_chan->xmit_enabled) + cyg_drv_interrupt_unmask(sdtr_chan->tx_int_num); +} + +// Serial I/O - low level interrupt handler (ISR) +static cyg_uint32 +sleb_sdtr_rx_ISR(cyg_vector_t vector, cyg_addrword_t data) +{ + serial_channel *chan = (serial_channel *)data; + sleb_sdtr_info *sdtr_chan = (sleb_sdtr_info *)chan->dev_priv; + cyg_drv_interrupt_mask(sdtr_chan->rx_int_num); + return CYG_ISR_CALL_DSR; // Cause DSR to be run +} + +// Serial I/O - high level interrupt handler (DSR) +static void +sleb_sdtr_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + serial_channel *chan = (serial_channel *)data; + sleb_sdtr_info *sdtr_chan = (sleb_sdtr_info *)chan->dev_priv; + CYG_ADDRWORD port = sdtr_chan->base; + cyg_uint8 status, c; + HAL_SPARC_86940_READ(SDTR_STATUS(port), status); + if ((status & SDTR_STAT_RxRDY) != 0) { + HAL_SPARC_86940_READ(SDTR_RXDATA(port), c); + (chan->callbacks->rcv_char)(chan, c); + } + cyg_drv_interrupt_acknowledge(sdtr_chan->rx_int_num); + cyg_drv_interrupt_unmask(sdtr_chan->rx_int_num); +} + +#endif // CYGPKG_IO_SERIAL_SPARCLITE_SLEB
