📄 sci.c
字号:
/* * /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.com/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. * * $Id: sci.c,v 1.9.2.1 2003/09/04 18:45:57 joel Exp $ */#include <rtems.h>#include <stdlib.h>#include <rtems/libio.h>#include <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 B9600 | CS8#define SH_SCI_DEF_COMM_1 B38400 | CS8/* #define SH_SCI_DEF_COMM_1 B9600 | CS8 */struct scidev_t { char * name ; unsigned32 addr ; rtems_device_minor_number minor ; unsigned short opened ; tcflag_t cflags ;} 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 UNUSEDstatic sci_setup_t sio_param[2];#endif/* imported from scitab.rel */extern int _sci_get_brparms( tcflag_t cflag, unsigned char *smr, unsigned char *brr );/* Translate termios' tcflag_t into sci settings */static int _sci_set_cflags( struct scidev_t *sci_dev, tcflag_t c_cflag ){ unsigned8 smr ; unsigned8 brr ; if ( c_cflag & CBAUD ) { if ( _sci_get_brparms( c_cflag, &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 */rtems_boolean wrtSCI0(unsigned char ch){ unsigned8 temp; rtems_boolean 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 */rtems_boolean wrtSCI1(unsigned char ch){ unsigned8 temp; rtems_boolean 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 */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 */void outbyte( rtems_device_minor_number minor, char ch){ sh_sci_outbyte_polled(minor, (unsigned char)ch);} /* outbyte */rtems_boolean rdSCI0(unsigned char *ch){ unsigned8 temp; rtems_boolean 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 */rtems_boolean rdSCI1(unsigned char *ch){ unsigned8 temp; rtems_boolean 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 */char sh_sci_inbyte_polled( rtems_device_minor_number minor ){ char ch; 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 */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; rtems_driver_name_t driver; /* * 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++ ) { status = rtems_io_lookup_name( sci_device[i].name, &driver); if( status != RTEMS_SUCCESSFUL ) { /* 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 ){ unsigned8 temp8; unsigned16 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 ); 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; char ch; 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 int _sh_sci_poll_write(int minor, const char *buf, int len){ int 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);}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( rtems_boolean poll ){ return poll ? &sci_poll_callbacks : &sci_interrupt_callbacks;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -