diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-12-08 13:31:12 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-12-08 13:31:12 +0100 |
commit | 533e2c0af6dad96de5c8123206adebea2fbb06d2 (patch) | |
tree | fdff3fdd8c09aac5b809d672399c634062871662 /c/src/lib/libbsp/sh/gensh2/console | |
parent | bsp/gensh1: Move libcpu files to BSP (diff) | |
download | rtems-533e2c0af6dad96de5c8123206adebea2fbb06d2.tar.bz2 |
bsp/gensh2: Move libcpu files to BSP
Update #3254.
Diffstat (limited to 'c/src/lib/libbsp/sh/gensh2/console')
-rw-r--r-- | c/src/lib/libbsp/sh/gensh2/console/sci.c | 554 | ||||
-rw-r--r-- | c/src/lib/libbsp/sh/gensh2/console/sci_termios.c | 449 |
2 files changed, 1003 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sh/gensh2/console/sci.c b/c/src/lib/libbsp/sh/gensh2/console/sci.c new file mode 100644 index 0000000000..143fc1bb94 --- /dev/null +++ b/c/src/lib/libbsp/sh/gensh2/console/sci.c @@ -0,0 +1,554 @@ +/* + * /dev/sci[0|1] for Hitachi SH 704X + * + * The SH doesn't have a designated console device. Therefore we "alias" + * another device as /dev/console and revector all calls to /dev/console + * to this device. + * + * This approach is similar to installing a sym-link from one device to + * another device. If rtems once will support sym-links for devices files, + * this implementation could be dropped. + */ + +/* + * Author: Ralf Corsepius (corsepiu@faw.uni-ulm.de) + * + * COPYRIGHT (c) 1997-1998, FAW Ulm, Germany + * + * This program 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. + * + * + * COPYRIGHT (c) 1998. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + * Modified to reflect sh7045 processor: + * John M. Mills (jmills@tga.com) + * TGA Technologies, Inc. + * 100 Pinnacle Way, Suite 140 + * Norcross, GA 30071 U.S.A. + * + * This modified file may be copied and distributed in accordance + * the above-referenced license. It is provided for critique and + * developmental purposes without any warranty nor representation + * by the authors or by TGA Technologies. + */ + +#include <bsp.h> + + +#include <stdlib.h> + +#include <rtems/libio.h> +#include <rtems/iosupp.h> +#include <rtems/score/sh_io.h> +#include <rtems/score/ispsh7045.h> +#include <rtems/score/iosh7045.h> +#include <sh/sh7_sci.h> +#include <sh/sh7_pfc.h> + +#include <sh/sci.h> + +#ifndef STANDALONE_EVB +#define STANDALONE_EVB 0 +#endif + +/* + * NOTE: Some SH variants have 3 sci devices + */ + +#define SCI_MINOR_DEVICES 2 + +/* + * FIXME: sh7045 register names match Hitachi data book, + * but conflict with RTEMS sh7032 usage. + */ + +#define SH_SCI_BASE_0 SCI_SMR0 +#define SH_SCI_BASE_1 SCI_SMR1 + +#define SH_SCI_DEF_COMM_0 CS8, B9600 +#define SH_SCI_DEF_COMM_1 CS8, B38400 +/* #define SH_SCI_DEF_COMM_1 CS8, B9600 */ + +struct scidev_t { + char * name; + uint32_t addr; + rtems_device_minor_number minor; + unsigned short opened; + tcflag_t cflags; + speed_t spd; +} sci_device[SCI_MINOR_DEVICES] = +{ + { "/dev/sci0", SH_SCI_BASE_0, 0, 0, SH_SCI_DEF_COMM_0 }, + { "/dev/sci1", SH_SCI_BASE_1, 1, 0, SH_SCI_DEF_COMM_1 } +}; + +/* local data structures maintain hardware configuration */ +#if UNUSED +static sci_setup_t sio_param[2]; +#endif + +/* Translate termios' tcflag_t into sci settings */ +static int _sci_set_cflags( + struct scidev_t *sci_dev, + tcflag_t c_cflag, + speed_t spd +) +{ + uint8_t smr; + uint8_t brr; + + if ( spd ) + { + if ( _sci_get_brparms( spd, &smr, &brr ) != 0 ) + return -1; + } + + if ( c_cflag & CSIZE ) + { + if ( c_cflag & CS8 ) + smr &= ~SCI_SEVEN_BIT_DATA; + else if ( c_cflag & CS7 ) + smr |= SCI_SEVEN_BIT_DATA; + else + return -1; + } + + if ( c_cflag & CSTOPB ) + smr |= SCI_STOP_BITS_2; + else + smr &= ~SCI_STOP_BITS_2; + + if ( c_cflag & PARENB ) + smr |= SCI_PARITY_ON; + else + smr &= ~SCI_PARITY_ON; + + if ( c_cflag & PARODD ) + smr |= SCI_ODD_PARITY; + else + smr &= ~SCI_ODD_PARITY; + + write8( smr, sci_dev->addr + SCI_SMR ); + write8( brr, sci_dev->addr + SCI_BRR ); + + return 0; +} + +/* + * local functions operate SCI ports 0 and 1 + * called from polling routines or ISRs + */ +static bool wrtSCI0(unsigned char ch) +{ + uint8_t temp; + bool result = false; + + if ((read8(SCI_SSR0) & SCI_TDRE) != 0x00) { + /* Write the character to the TDR */ + write8(ch, SCI_TDR0); + /* Clear the TDRE bit */ + temp = read8(SCI_SSR0) & ~SCI_TDRE; + write8(temp, SCI_SSR0); + result = true; + } + return result; +} /* wrtSCI0 */ + +static bool wrtSCI1(unsigned char ch) +{ + uint8_t temp; + bool result = false; + + if ((read8(SCI_SSR1) & SCI_TDRE) != 0x00) { + /* Write the character to the TDR */ + write8(ch, SCI_TDR1); + /* Clear the TDRE bit */ + temp = read8(SCI_SSR1) & ~SCI_TDRE; + write8(temp, SCI_SSR1); + result = true; + } + return result; +} /* wrtSCI1 */ + +/* polled output steers byte to selected port */ +static void sh_sci_outbyte_polled( + rtems_device_minor_number minor, + char ch ) +{ + if (minor == 0) /* blocks until port ready */ + while (wrtSCI0(ch) != true); /* SCI0*/ + else + while (wrtSCI1(ch) != true); /* SCI1*/ +} /* sh_sci_outbyte_polled */ + +/* + * Initial version calls polled output driver and blocks + */ +static void outbyte( + rtems_device_minor_number minor, + char ch) +{ + sh_sci_outbyte_polled(minor, (unsigned char)ch); +} /* outbyte */ + +static bool rdSCI0(unsigned char *ch) +{ + uint8_t temp; + bool result = false; + + if ((read8(SCI_SSR0) & SCI_RDRF) != 0x00) { + /* read input */ + *ch = read8(SCI_RDR0); + /* Clear RDRF flag */ + temp = read8(SCI_SSR0) & ~SCI_RDRF; + write8(temp, SCI_SSR0); + /* Check for transmission errors */ + if (temp & (SCI_ORER | SCI_FER | SCI_PER)) { + /* TODO: report to RTEMS transmission error */ + + /* clear error flags*/ + temp &= ~(SCI_ORER | SCI_FER | SCI_PER); + write8(temp, SCI_SSR0); + } + result = true; + } + return result; +} /* rdSCI0 */ + +static bool rdSCI1(unsigned char *ch) +{ + uint8_t temp; + bool result = false; + + if ((read8(SCI_SSR1) & SCI_RDRF) != 0x00) { + /* read input */ + *ch = read8(SCI_RDR1); + /* Clear RDRF flag */ + temp= read8(SCI_SSR1) & ~SCI_RDRF; + write8(temp, SCI_SSR1); + /* Check for transmission errors */ + if (temp & (SCI_ORER | SCI_FER | SCI_PER)) { + /* TODO: report to RTEMS transmission error */ + + /* clear error flags*/ + temp &= ~(SCI_ORER | SCI_FER | SCI_PER); + write8(temp, SCI_SSR1); + } + result = true; + } + return result; +} /* rdSCI1 */ + +/* initial version pulls byte from selected port */ +static char sh_sci_inbyte_polled( rtems_device_minor_number minor ) +{ + uint8_t ch = 0; + + if (minor == 0) /* blocks until char.ready */ + while (rdSCI0(&ch) != true); /* SCI0 */ + else + while (rdSCI1(&ch) != true); /* SCI1 */ + return ch; +} /* sh_sci_inbyte_polled */ + +/* Initial version calls polled input driver */ +static char inbyte( rtems_device_minor_number minor ) +{ + char ch; + + ch = sh_sci_inbyte_polled(minor); + return ch; +} /* inbyte */ + +/* sh_sci_initialize + * + * This routine initializes (registers) the sh_sci IO drivers. + * + * Input parameters: ignored + * + * Output parameters: NONE + * + * Return values: RTEMS_SUCCESSFUL + * if all sci[...] register, else calls + * rtems_fatal_error_occurred(status) + */ +rtems_device_driver sh_sci_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg ) +{ + rtems_device_driver status; + rtems_device_minor_number i; + + /* + * register all possible devices. + * the initialization of the hardware is done by sci_open + * + * One of devices could be previously registered by console + * initialization therefore we check it everytime + */ + for ( i = 0 ; i < SCI_MINOR_DEVICES ; i++ ) { + /* OK. We assume it is not registered yet. */ + status = rtems_io_register_name( + sci_device[i].name, + major, + sci_device[i].minor + ); + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + } + + /* non-default hardware setup occurs in sh_sci_open() */ + return RTEMS_SUCCESSFUL; +} + +/* + * Open entry point + * Sets up port and pins for selected sci. + */ +rtems_device_driver sh_sci_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg ) +{ + uint8_t temp8; + uint16_t temp16; + + unsigned a; + + /* check for valid minor number */ + if (( minor > ( SCI_MINOR_DEVICES -1 )) || ( minor < 0 )) { + return RTEMS_INVALID_NUMBER; + } + + /* device already opened */ + if ( sci_device[minor].opened > 0 ) { + sci_device[minor].opened++; + return RTEMS_SUCCESSFUL; + } + + /* set PFC registers to enable I/O pins */ + + if ((minor == 0)) { + temp16 = read16(PFC_PACRL2); /* disable SCK0, DMA, IRQ */ + temp16 &= ~(PA2MD1 | PA2MD0); + temp16 |= (PA_TXD0 | PA_RXD0); /* enable pins for Tx0, Rx0 */ + write16(temp16, PFC_PACRL2); + + } else if (minor == 1) { + temp16 = read16(PFC_PACRL2); /* disable SCK1, DMA, IRQ */ + temp16 &= ~(PA5MD1 | PA5MD0); + temp16 |= (PA_TXD1 | PA_RXD1); /* enable pins for Tx1, Rx1 */ + write16(temp16, PFC_PACRL2); + + } /* add other devices and pins as req'd. */ + + /* set up SCI registers */ + write8(0x00, sci_device[minor].addr + SCI_SCR); /* Clear SCR */ + /* set SMR and BRR */ + _sci_set_cflags( &sci_device[minor], sci_device[minor].cflags, sci_device[minor].spd ); + + for (a=0; a < 10000L; a++) { /* Delay */ + __asm__ volatile ("nop"); + } + + write8((SCI_RE | SCI_TE), /* enable async. Tx and Rx */ + sci_device[minor].addr + SCI_SCR); + + /* clear error flags */ + temp8 = read8(sci_device[minor].addr + SCI_SSR); + while (temp8 & (SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER)) { + temp8 = read8(sci_device[minor].addr + SCI_RDR); /* flush input */ + temp8 = read8(sci_device[minor].addr + SCI_SSR); /* clear some flags */ + write8(temp8 & ~(SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER), + sci_device[minor].addr + SCI_SSR); + temp8 = read8(sci_device[minor].addr + SCI_SSR); /* check if everything is OK */ + } + /* Clear RDRF flag */ + write8(0x00, sci_device[minor].addr + SCI_TDR); /* force output */ + /* Clear the TDRE bit */ + temp8 = read8(sci_device[minor].addr + SCI_SSR) & ~SCI_TDRE; + write8(temp8, sci_device[minor].addr + SCI_SSR); + + /* add interrupt setup if required */ + + + sci_device[minor].opened++; + + return RTEMS_SUCCESSFUL; +} + +/* + * Close entry point + */ +rtems_device_driver sh_sci_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + /* FIXME: Incomplete */ + if ( sci_device[minor].opened > 0 ) + sci_device[minor].opened--; + else + return RTEMS_INVALID_NUMBER; + + return RTEMS_SUCCESSFUL; +} + +/* + * read bytes from the serial port. We only have stdin. + */ +rtems_device_driver sh_sci_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + rtems_libio_rw_args_t *rw_args; + char *buffer; + int maximum; + int count = 0; + + rw_args = (rtems_libio_rw_args_t *) arg; + + buffer = rw_args->buffer; + maximum = rw_args->count; + + for (count = 0; count < maximum; count++) { + buffer[ count ] = inbyte(minor); + if (buffer[ count ] == '\n' || buffer[ count ] == '\r') { + buffer[ count++ ] = '\n'; + break; + } + } + + rw_args->bytes_moved = count; + return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED; +} + +/* + * write bytes to the serial port. Stdout and stderr are the same. + */ +rtems_device_driver sh_sci_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + int count; + int maximum; + rtems_libio_rw_args_t *rw_args; + char *buffer; + + rw_args = (rtems_libio_rw_args_t *) arg; + + buffer = rw_args->buffer; + maximum = rw_args->count; + + for (count = 0; count < maximum; count++) { + if ( buffer[ count ] == '\n') { + outbyte(minor, '\r'); + } + outbyte( minor, buffer[ count ] ); + } + + rw_args->bytes_moved = maximum; + return 0; +} + +/* + * IO Control entry point + */ +rtems_device_driver sh_sci_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void * arg +) +{ + /* Not yet supported */ + return RTEMS_SUCCESSFUL; +} + +/* + * Termios polled first open + */ +static int _sh_sci_poll_first_open(int major, int minor, void *arg) +{ + return sh_sci_open(major, minor, arg); +} + +/* + * Termios general last close + */ +static int _sh_sci_last_close(int major, int minor, void *arg) +{ + return sh_sci_close(major, minor, arg); +} + +/* + * Termios polled read + */ +static int _sh_sci_poll_read(int minor) +{ + int value = -1; + uint8_t ch = 0; + + if ( minor == 0 ) { + if ( rdSCI0( &ch ) ) + value = (int) ch; + } else if ( minor == 1 ) { + if ( rdSCI1( &ch ) ) + value = (int) ch; + } + return value; +} + +/* + * Termios polled write + */ +static ssize_t _sh_sci_poll_write(int minor, const char *buf, size_t len) +{ + size_t count; + + for (count = 0; count < len; count++) + outbyte( minor, buf[count] ); + return count; +} + +/* + * Termios set attributes + */ +static int _sh_sci_set_attributes( int minor, const struct termios *t) +{ + return _sci_set_cflags( &sci_device[ minor ], t->c_cflag, t->c_ospeed); +} + + +const rtems_termios_callbacks sci_poll_callbacks = { + _sh_sci_poll_first_open, /* FirstOpen*/ + _sh_sci_last_close, /* LastClose*/ + _sh_sci_poll_read, /* PollRead */ + _sh_sci_poll_write, /* Write */ + _sh_sci_set_attributes, /* setAttributes */ + NULL, /* stopRemoteTX */ + NULL, /* StartRemoteTX */ + 0 /* outputUsesInterrupts */ +}; + +/* FIXME: not yet supported */ +const rtems_termios_callbacks sci_interrupt_callbacks; + +const rtems_termios_callbacks* sh_sci_get_termios_handlers( bool poll ) +{ + return poll ? + &sci_poll_callbacks : + &sci_interrupt_callbacks; +} diff --git a/c/src/lib/libbsp/sh/gensh2/console/sci_termios.c b/c/src/lib/libbsp/sh/gensh2/console/sci_termios.c new file mode 100644 index 0000000000..5d588065af --- /dev/null +++ b/c/src/lib/libbsp/sh/gensh2/console/sci_termios.c @@ -0,0 +1,449 @@ +/* + * Termios console serial driver. + */ + +/* + * Based on SCI driver by Ralf Corsepius and John M. Mills + * + * Author: Radzislaw Galler <rgaller@et.put.poznan.pl> + * + * COPYRIGHT (c) 1989-2001. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + */ + +#include <bsp.h> +#include <stdlib.h> + +#include <libchip/serial.h> +#include <libchip/sersupp.h> + +#include <rtems/libio.h> +#include <rtems/iosupp.h> + +#include <rtems/score/sh_io.h> +#include <rtems/score/ispsh7045.h> +#include <rtems/score/iosh7045.h> + +#include <sh/sh7_sci.h> +#include <sh/sh7_pfc.h> +#include <sh/sci_termios.h> + + +/* + * Some handy macros + */ +#define SH_SCI_REG_DATA(_data, _minor, _register) \ + (write8(_data, Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register))) + +#define SH_SCI_REG_FLAG(_flag, _minor, _register) \ + (write8(read8(Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)) | (_flag), \ + Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register))) + +#define SH_SCI_REG_MASK(_flag, _minor, _register) \ + (write8(read8(Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register)) & ~(_flag),\ + Console_Port_Tbl[_minor]->ulCtrlPort1 + (_register))) + +/* + * NOTE: Some SH variants have 3 sci devices + */ + +#define SCI_MINOR_DEVICES 2 + + +/* + * Automatically generated function imported from scitab.rel + */ +extern int _sci_get_brparms( + speed_t spd, + unsigned char *smr, + unsigned char *brr +); + +/* + * Translate termios flags into SCI settings + */ +int sh_sci_set_attributes( + int minor, + const struct termios *t +) +{ + uint8_t smr; + uint8_t brr; + int a; + + tcflag_t c_cflag = t->c_cflag; + speed_t spd = t->c_ospeed; + + if ( spd ) { + if ( _sci_get_brparms( spd, &smr, &brr ) != 0 ) + return -1 ; + } + + if ( c_cflag & CSIZE ) { + if ( c_cflag & CS8 ) + smr &= ~SCI_SEVEN_BIT_DATA; + else if ( c_cflag & CS7 ) + smr |= SCI_SEVEN_BIT_DATA; + else + return -1 ; + } + + if ( c_cflag & CSTOPB ) + smr |= SCI_STOP_BITS_2; + else + smr &= ~SCI_STOP_BITS_2; + + if ( c_cflag & PARENB ) + smr |= SCI_PARITY_ON ; + else + smr &= ~SCI_PARITY_ON ; + + if ( c_cflag & PARODD ) + smr |= SCI_ODD_PARITY ; + else + smr &= ~SCI_ODD_PARITY; + + SH_SCI_REG_MASK((SCI_RE | SCI_TE), minor, SCI_SCR); + + SH_SCI_REG_DATA(smr, minor, SCI_SMR); + SH_SCI_REG_DATA(brr, minor, SCI_BRR); + + for (a=0; a < 10000L; a++) { /* Delay one bit */ + __asm__ volatile ("nop"); + } + + SH_SCI_REG_FLAG((SCI_RE | SCI_TE), minor, SCI_SCR); + + return 0; +} + +/* + * Receive-data-full ISR + * + * The same routine for all interrupt sources of the same type. + */ +static rtems_isr sh_sci_rx_isr(rtems_vector_number vector) +{ + int minor; + + for (minor = 0; minor < Console_Port_Count; minor++) { + if (Console_Port_Tbl[minor]->ulIntVector == vector) { + char temp8; + + /* + * FIXME: error handling should be added + */ + temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_RDR); + + rtems_termios_enqueue_raw_characters( + Console_Port_Data[minor].termios_data, &temp8, 1); + + SH_SCI_REG_MASK(SCI_RDRF, minor, SCI_SSR); + break; + } + } +} + +/* + * Transmit-data-empty ISR + * + * The same routine for all interrupt sources of the same type. + */ +static rtems_isr sh_sci_tx_isr(rtems_vector_number vector) +{ + int minor; + + for (minor = 0; minor < Console_Port_Count; minor++) { + if (Console_Port_Tbl[minor]->ulDataPort == vector) { + /* + * FIXME: Error handling should be added + */ + + /* + * Mask end-of-transmission interrupt + */ + SH_SCI_REG_MASK(SCI_TIE, minor, SCI_SCR); + + if (rtems_termios_dequeue_characters( + Console_Port_Data[minor].termios_data, 1)) { + /* + * More characters to be received - interrupt must be enabled + */ + SH_SCI_REG_FLAG(SCI_TIE, minor, SCI_SCR); + } + break; + } + } +} + + +/* + * Initialization of serial port + */ +void sh_sci_init(int minor) +{ + uint16_t temp16; + + /* + * set PFC registers to enable I/O pins + */ + if ((minor == 0)) { + temp16 = read16(PFC_PACRL2); /* disable SCK0, DMA, IRQ */ + temp16 &= ~(PA2MD1 | PA2MD0); + temp16 |= (PA_TXD0 | PA_RXD0); /* enable pins for Tx0, Rx0 */ + write16(temp16, PFC_PACRL2); + + } else if (minor == 1) { + temp16 = read16(PFC_PACRL2); /* disable SCK1, DMA, IRQ */ + temp16 &= ~(PA5MD1 | PA5MD0); + temp16 |= (PA_TXD1 | PA_RXD1); /* enable pins for Tx1, Rx1 */ + write16(temp16, PFC_PACRL2); + } + + /* + * Non-default hardware setup occurs in sh_sci_first_open + */ +} + +/* + * Initialization of interrupts + * + * Interrupts can be started only after opening a device, so interrupt + * flags are set up in sh_sci_first_open function + */ +void sh_sci_initialize_interrupts(int minor) +{ + rtems_isr_entry old_isr; + rtems_status_code status; + + sh_sci_init(minor); + /* + * Disable IRQ of SCIx + */ + status = sh_set_irq_priority( Console_Port_Tbl[minor]->ulIntVector, 0); + + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + + SH_SCI_REG_MASK(SCI_RIE, minor, SCI_SCR); + + /* + * Catch apropriate vectors + */ + status = rtems_interrupt_catch( + sh_sci_rx_isr, + Console_Port_Tbl[minor]->ulIntVector, + &old_isr); + + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + + status = rtems_interrupt_catch( + sh_sci_tx_isr, + Console_Port_Tbl[minor]->ulDataPort, + &old_isr); + + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); + + /* + * Enable IRQ of SCIx + */ + SH_SCI_REG_FLAG(SCI_RIE, minor, SCI_SCR); + + status = sh_set_irq_priority( + Console_Port_Tbl[minor]->ulIntVector, + Console_Port_Tbl[minor]->ulCtrlPort2); + + if (status != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(status); +} + + +/* + * Open entry point + * Sets up port and pins for selected sci. + */ + +int sh_sci_first_open( + int major, + int minor, + void *arg +) +{ + char temp8; + unsigned int a ; + + /* + * check for valid minor number + */ + if (( minor > ( SCI_MINOR_DEVICES -1 )) || ( minor < 0 )) { + return RTEMS_INVALID_NUMBER; + } + + /* + * set up SCI registers + */ + /* Clear SCR - disable Tx and Rx */ + SH_SCI_REG_DATA(0x00, minor, SCI_SCR); + + /* set SMR and BRR - baudrate and format */ + sh_sci_set_attributes(minor, Console_Port_Tbl[minor]->pDeviceParams); + + for (a=0; a < 10000L; a++) { /* Delay */ + __asm__ volatile ("nop"); + } + + write8((SCI_RE | SCI_TE), /* enable async. Tx and Rx */ + Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SCR); + + /* + * clear error flags + */ + temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR); + while(temp8 & (SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER)) { + /* flush input */ + temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_RDR); + + /* clear some flags */ + SH_SCI_REG_FLAG((SCI_RDRF|SCI_ORER|SCI_FER|SCI_PER), minor, SCI_SSR); + + /* check if everything is OK */ + temp8 = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR); + } + + /* Clear RDRF flag */ + SH_SCI_REG_DATA(0x00, minor, SCI_TDR); /* force output */ + + /* Clear the TDRE bit */ + SH_SCI_REG_FLAG(SCI_TDRE, minor, SCI_SSR); + + /* + * Interrupt setup + */ + if (Console_Port_Tbl[minor]->pDeviceFns->deviceOutputUsesInterrupts) { + SH_SCI_REG_FLAG(SCI_RIE, minor, SCI_SCR); + } + + return RTEMS_SUCCESSFUL ; +} + +/* + * Close entry point + */ + +int sh_sci_last_close( + int major, + int minor, + void *arg +) +{ + /* FIXME: Incomplete */ + + /* Shutdown interrupts if necessary */ + if (Console_Port_Tbl[minor]->pDeviceFns->deviceOutputUsesInterrupts) + { + SH_SCI_REG_MASK((SCI_TIE | SCI_RIE), minor, SCI_SCR); + } + return RTEMS_SUCCESSFUL ; +} + +/* + * Interrupt aware write routine + */ +ssize_t sh_sci_write_support_int( + int minor, + const char *buf, + size_t len +) +{ + if (!len) + return 0; + /* + * Put data into TDR and clear transmission-end-flag + */ + SH_SCI_REG_DATA(*buf, minor, SCI_TDR); + SH_SCI_REG_MASK(SCI_TDRE, minor, SCI_SSR); + /* + * Enable interrupt + */ + SH_SCI_REG_FLAG(SCI_TIE, minor, SCI_SCR); + + return 1; +} + +/* + * Polled write method + */ +ssize_t sh_sci_write_support_polled( + int minor, + const char *buf, + size_t len +) +{ + int count = 0; + + while(count < len) { + sh_sci_write_polled(minor, buf[count]); + count++; + } + /* + * Return number of bytes written + */ + return count; +} + +/* + * Polled write of one character at a time + */ +void sh_sci_write_polled( + int minor, + char c +) +{ + /* + * Wait for end of previous character + */ + while(!(read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR) & SCI_TDRE)); + /* + * Send the character + */ + SH_SCI_REG_DATA(c, minor, SCI_TDR); + + /* + * Clear TDRE flag + */ + SH_SCI_REG_MASK(SCI_TDRE, minor, SCI_SSR); +} + +/* + * Non-blocking read + */ +int sh_sci_inbyte_nonblocking_polled(int minor) +{ + char inbyte; + + /* + * Check if input buffer is full + */ + if (read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR) & SCI_RDRF) { + inbyte = read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_RDR); + SH_SCI_REG_MASK(SCI_RDRF, minor, SCI_SSR); + + /* + * Check for errors + */ + if (read8(Console_Port_Tbl[minor]->ulCtrlPort1 + SCI_SSR) & + (SCI_ORER | SCI_FER | SCI_PER)) { + SH_SCI_REG_MASK((SCI_ORER | SCI_FER | SCI_PER), minor, SCI_SSR); + return -1; + } + return (int)inbyte; + } + return -1; +} |