summaryrefslogtreecommitdiffstats
path: root/bsps/m68k/mrm332/console/sci.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/m68k/mrm332/console/sci.c')
-rw-r--r--bsps/m68k/mrm332/console/sci.c1586
1 files changed, 1586 insertions, 0 deletions
diff --git a/bsps/m68k/mrm332/console/sci.c b/bsps/m68k/mrm332/console/sci.c
new file mode 100644
index 0000000000..c6b4933f13
--- /dev/null
+++ b/bsps/m68k/mrm332/console/sci.c
@@ -0,0 +1,1586 @@
+/*****************************************************************************
+* File: sci.c
+*
+* Desc: This file contains the console IO routines for the SCI port.
+* There are two interfaces in this module. One is for the rtems
+* termios/console code and the other is a device driver interface.
+* This module works together with the termio module which is
+* sometimes referred to as the "line disciplines" which implements
+* terminal i/o processing like tabs, backspaces, and newlines.
+* The rtems printf uses interrupt io and the rtems printk routine
+* uses polled io which is better for debugging.
+*
+* Index: Documentation
+* Section A - Include Files
+* Section B - Manifest Constants
+* Section C - External Data
+* Section D - External Functions
+* Section E - Local Functions
+* Section F - Local Variables
+* Section G - A circular data buffer for rcv chars
+* Section H - RTEMS termios callbacks for the interrupt api
+* Section I - RTEMS termios callbacks for the polled api
+
+* Section 0 - Miscellaneous routines
+* Section 1 - Routines to manipulate the circular buffer
+* Section 2 - Interrupt based entry points for the termios module
+* Section 3 - Polling based entry points for the termios module
+* Section 4 - Device driver public api entry points
+* Section 5 - Hardware level routines
+* Section 6 - Testing and debugging code
+*
+* Refer: Motorola QSM Reference Manual - Chapter 5 - SCI sub-module
+*
+* Note: See bsp.h,confdefs.h,system.h for installing drivers into RTEMS.
+*
+*****************************************************************************/
+
+/*****************************************************************************
+ Overview of serial port console terminal input/output
+*****************************************************************************/
+
+/*
+ +-----------+ +---------+
+ | app | | app |
+ +-----------+ +---------+
+ | |
+ | (printf,scanf,etc.) |
+ v |
+ +-----------+ |
+ | libc | |
+ +-----------+ |
+ | |
+ | |
+ | (open,close,read,write,ioctl) |
+ ======|==========================================|========================
+ | /dev/console | /dev/sci
+ | (stdin,stdout,stderr) |
+ ======|==========================================|========================
+ | |
+ | |
+ v v
+ +-----------+ +-----------+ +---------+
+ | console | <---> | termios | <---> | sci |
+ | driver | | module | | driver |
+ +-----------+ +-----------+ +---------+
+ |
+ |
+ v
+ +---------+
+ | |
+ | uart |
+ | |
+ +---------+
+*/
+
+
+/*****************************************************************************
+ Section A - Include Files
+*****************************************************************************/
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <stdio.h>
+#include <rtems/libio.h>
+#include <libchip/serial.h>
+#include <libchip/sersupp.h>
+#include "sci.h"
+#include <rtems/m68k/qsm.h>
+#include <inttypes.h>
+/*#include "../misc/include/cpu332.h" */
+
+/*****************************************************************************
+ Section B - Manifest Constants
+*****************************************************************************/
+
+#define SCI_MINOR 0 /* minor device number */
+
+/* IMPORTANT - if the device driver api is opened, it means the sci is being
+ * used for direct hardware access, so other users (like termios) get ignored
+ */
+#define DRIVER_CLOSED 0 /* the device driver api is closed */
+#define DRIVER_OPENED 1 /* the device driver api is opened */
+
+/* system clock definitions, i dont have documentation on this... */
+
+#if 0 /* Not needed, this is provided in mrm332.h */
+#define XTAL 32768.0 /* crystal frequency in Hz */
+#define NUMB_W 0 /* system clock parameters */
+#define NUMB_X 1
+#define NUMB_Y 0x38 /* for 14.942 Mhz */
+#define NUMB_Y 0x3F /* for 16.777 Mhz */
+
+#define SYS_CLOCK (XTAL * 4.0 * (NUMB_Y+1) * (1 << (2 * NUMB_W + NUMB_X)))
+
+#endif
+
+
+/*****************************************************************************
+ Section C - External Data
+*****************************************************************************/
+
+
+
+/*****************************************************************************
+ Section D - External Functions
+*****************************************************************************/
+
+
+
+/*****************************************************************************
+ Section E - Local Functions
+*****************************************************************************/
+
+void SCI_output_char(char c);
+
+/*rtems_isr SciIsr( rtems_vector_number vector ); interrupt handler */
+
+const rtems_termios_callbacks * SciGetTermiosHandlers( int32_t polled );
+
+rtems_device_driver SciInitialize( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciOpen( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciClose( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciRead( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciWrite( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciControl( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciRead (
+ rtems_device_major_number, rtems_device_minor_number, void *);
+
+rtems_isr SciIsr( rtems_vector_number vector );
+
+int SciInterruptOpen(int, int, void *); /* termios api */
+int SciInterruptClose(int, int, void *); /* termios api */
+ssize_t SciInterruptWrite(int, const char *, size_t); /* termios api */
+
+int SciSetAttributes(int, const struct termios*); /* termios api */
+int SciPolledOpen(int, int, void *); /* termios api */
+int SciPolledClose(int, int, void *); /* termios api */
+int SciPolledRead(int); /* termios api */
+ssize_t SciPolledWrite(int, const char *, size_t); /* termios api */
+
+static void SciSetBaud(uint32_t rate); /* hardware routine */
+static void SciSetDataBits(uint16_t bits); /* hardware routine */
+static void SciSetParity(uint16_t parity); /* hardware routine */
+
+static void inline SciDisableAllInterrupts( void ); /* hardware routine */
+static void inline SciDisableTransmitInterrupts( void );/* hardware routine */
+static void inline SciDisableReceiveInterrupts( void ); /* hardware routine */
+
+static void inline SciEnableTransmitInterrupts( void ); /* hardware routine */
+static void inline SciEnableReceiveInterrupts( void ); /* hardware routine */
+
+static void inline SciDisableReceiver( void ); /* hardware routine */
+static void inline SciDisableTransmitter( void ); /* hardware routine */
+
+static void inline SciEnableReceiver( void ); /* hardware routine */
+static void inline SciEnableTransmitter( void ); /* hardware routine */
+
+void SciWriteCharWait ( uint8_t ); /* hardware routine */
+void SciWriteCharNoWait( uint8_t ); /* hardware routine */
+
+uint8_t inline SciCharAvailable( void ); /* hardware routine */
+
+static uint8_t inline SciReadCharWait( void ); /* hardware routine */
+static uint8_t inline SciReadCharNoWait( void ); /* hardware routine */
+
+void SciSendBreak( void ); /* test routine */
+
+static int8_t SciRcvBufGetChar(void); /* circular rcv buf */
+static void SciRcvBufPutChar( uint8_t); /* circular rcv buf */
+#if 0
+static void SciRcvBufFlush( void ); /* unused routine */
+#endif
+
+void SciUnitTest(void); /* test routine */
+void SciPrintStats(void); /* test routine */
+
+
+/*****************************************************************************
+ Section F - Local Variables
+*****************************************************************************/
+
+static struct rtems_termios_tty *SciTermioTty;
+
+static uint8_t SciInited = 0; /* has the driver been inited */
+
+static uint8_t SciOpened; /* has the driver been opened */
+
+static uint8_t SciMajor; /* major device number */
+
+static uint16_t SciBaud; /* current value in baud register */
+
+static uint32_t SciBytesIn = 0; /* bytes received */
+static uint32_t SciBytesOut = 0; /* bytes transmitted */
+
+static uint32_t SciErrorsParity = 0; /* error counter */
+static uint32_t SciErrorsNoise = 0; /* error counter */
+static uint32_t SciErrorsFraming = 0; /* error counter */
+static uint32_t SciErrorsOverrun = 0; /* error counter */
+
+#if defined(CONSOLE_SCI)
+
+/* this is what rtems printk uses to do polling based output */
+
+BSP_output_char_function_type BSP_output_char = SCI_output_char;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
+#endif
+
+/*****************************************************************************
+ Section G - A circular buffer for rcv chars when the driver interface is used.
+*****************************************************************************/
+
+/* it is trivial to wrap your buffer pointers when size is a power of two */
+
+#define SCI_RCV_BUF_SIZE 256 /* must be a power of 2 !!! */
+
+/* if someone opens the sci device using the device driver interface,
+ * then the receive data interrupt handler will put characters in this buffer
+ * instead of sending them up to the termios module for the console
+ */
+static uint8_t SciRcvBuffer[SCI_RCV_BUF_SIZE];
+
+static uint8_t SciRcvBufPutIndex = 0; /* array index to put in next char */
+
+static uint8_t SciRcvBufGetIndex = 0; /* array index to take out next char */
+
+static uint16_t SciRcvBufCount = 0; /* how many bytes are in the buffer */
+
+
+
+/*****************************************************************************
+ Section H - RTEMS termios callbacks for the interrupt version of the driver
+*****************************************************************************/
+
+static const rtems_termios_callbacks SciInterruptCallbacks =
+{
+ SciInterruptOpen, /* first open */
+ SciInterruptClose, /* last close */
+ NULL, /* polled read (not required) */
+ SciInterruptWrite, /* write */
+ SciSetAttributes, /* set attributes */
+ NULL, /* stop remote xmit */
+ NULL, /* start remote xmit */
+ TRUE /* output uses interrupts */
+};
+
+/*****************************************************************************
+ Section I - RTEMS termios callbacks for the polled version of the driver
+*****************************************************************************/
+
+static const rtems_termios_callbacks SciPolledCallbacks =
+{
+ SciPolledOpen, /* first open */
+ SciPolledClose, /* last close */
+ SciPolledRead, /* polled read */
+ SciPolledWrite, /* write */
+ SciSetAttributes, /* set attributes */
+ NULL, /* stop remote xmit */
+ NULL, /* start remote xmit */
+ FALSE /* output uses interrupts */
+};
+
+
+/*
+ * SECTION 0
+ * MISCELLANEOUS ROUTINES
+ */
+
+/****************************************************************************
+ * Func: SCI_output_char
+ * Desc: used by rtems printk function to send a char to the uart
+ * Inputs: the character to transmit
+ * Outputs: none
+ * Errors: none
+ * Scope: public
+ ****************************************************************************/
+
+void SCI_output_char(char c)
+{
+/* ( minor device number, pointer to the character, length ) */
+
+ SciPolledWrite( SCI_MINOR, &c, 1);
+
+ return;
+}
+
+
+/****************************************************************************
+* Func: SciGetTermiosHandlers
+* Desc: returns a pointer to the table of serial io functions
+* this is called from console_open with polled set to false
+* Inputs: flag indicating whether we want polled or interrupt driven io
+* Outputs: pointer to function table
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+const rtems_termios_callbacks * SciGetTermiosHandlers( int32_t polled )
+{
+ if ( polled )
+ {
+ return &SciPolledCallbacks; /* polling based */
+ }
+ else
+ {
+ return &SciInterruptCallbacks; /* interrupt driven */
+ }
+}
+
+
+/****************************************************************************
+* Func: SciIsr
+* Desc: interrupt handler for serial communications interface
+* Inputs: vector number - unused
+* Outputs: none
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+rtems_isr SciIsr( rtems_vector_number vector )
+{
+ uint8_t ch;
+
+ if ( (*SCSR) & SCI_ERROR_PARITY ) SciErrorsParity ++;
+ if ( (*SCSR) & SCI_ERROR_FRAMING ) SciErrorsFraming ++;
+ if ( (*SCSR) & SCI_ERROR_NOISE ) SciErrorsNoise ++;
+ if ( (*SCSR) & SCI_ERROR_OVERRUN ) SciErrorsOverrun ++;
+
+ /* see if it was a transmit interrupt */
+ /* data reg empty, xmt complete */
+ if ( ( *SCCR1 & SCI_ENABLE_INT_TX ) && ( (*SCSR) & SCI_XMTR_AVAILABLE ) )
+ {
+ SciDisableTransmitInterrupts();
+
+ /* tell termios module that the charcter was sent */
+ /* he will call us later to transmit more if there are any */
+
+ if (rtems_termios_dequeue_characters( SciTermioTty, 1 ))
+ {
+ /* there are more bytes to transmit so enable TX interrupt */
+
+ SciEnableTransmitInterrupts();
+ }
+ }
+
+ /* see if it was a receive interrupt */
+ /* on the sci uart we just get one character per interrupt */
+
+ while ( SciCharAvailable() ) /* char in data register? */
+ {
+ ch = SciReadCharNoWait(); /* get the char from the uart */
+
+ /* IMPORTANT!!! */
+ /* either send it to the termios module or keep it locally */
+
+ if ( SciOpened == DRIVER_OPENED ) /* the driver is open */
+ {
+ SciRcvBufPutChar(ch); /* keep it locally */
+ }
+ else /* put in termios buffer */
+ {
+ char c = (char) ch;
+ rtems_termios_enqueue_raw_characters( SciTermioTty, &c, 1 );
+ }
+
+ *SCSR &= SCI_CLEAR_RX_INT; /* clear the interrupt */
+ }
+}
+
+
+/*
+ * SECTION 1
+ * ROUTINES TO MANIPULATE THE CIRCULAR BUFFER
+ */
+
+/****************************************************************************
+* Func: SciRcvBufGetChar
+* Desc: read a character from the circular buffer
+* make sure there is data before you call this!
+* Inputs: none
+* Outputs: the character or -1
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static int8_t SciRcvBufGetChar(void)
+{
+ rtems_interrupt_level level;
+ uint8_t ch;
+
+ if ( SciRcvBufCount == 0 )
+ {
+ rtems_fatal_error_occurred(0xDEAD); /* check the count first! */
+ }
+
+ rtems_interrupt_disable( level ); /* disable interrupts */
+
+ ch = SciRcvBuffer[SciRcvBufGetIndex]; /* get next byte */
+
+ SciRcvBufGetIndex++; /* bump the index */
+
+ SciRcvBufGetIndex &= SCI_RCV_BUF_SIZE - 1; /* and wrap it */
+
+ SciRcvBufCount--; /* decrement counter */
+
+ rtems_interrupt_enable( level ); /* restore interrupts */
+
+ return ch; /* return the char */
+}
+
+
+/****************************************************************************
+* Func: SciRcvBufPutChar
+* Desc: put a character into the rcv data circular buffer
+* Inputs: the character
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void SciRcvBufPutChar( uint8_t ch )
+{
+ rtems_interrupt_level level;
+
+ if ( SciRcvBufCount == SCI_RCV_BUF_SIZE ) /* is there room? */
+ {
+ return; /* no, throw it away */
+ }
+
+ rtems_interrupt_disable( level ); /* disable interrupts */
+
+ SciRcvBuffer[SciRcvBufPutIndex] = ch; /* put it in the buf */
+
+ SciRcvBufPutIndex++; /* bump the index */
+
+ SciRcvBufPutIndex &= SCI_RCV_BUF_SIZE - 1; /* and wrap it */
+
+ SciRcvBufCount++; /* increment counter */
+
+ rtems_interrupt_enable( level ); /* restore interrupts */
+
+ return; /* return */
+}
+
+
+/****************************************************************************
+* Func: SciRcvBufFlush
+* Desc: completely reset and clear the rcv buffer
+* Inputs: none
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+#if 0 /* prevents compiler warning */
+static void SciRcvBufFlush( void )
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable( level ); /* disable interrupts */
+
+ memset( SciRcvBuffer, 0, sizeof(SciRcvBuffer) );
+
+ SciRcvBufPutIndex = 0; /* clear */
+
+ SciRcvBufGetIndex = 0; /* clear */
+
+ SciRcvBufCount = 0; /* clear */
+
+ rtems_interrupt_enable( level ); /* restore interrupts */
+
+ return; /* return */
+}
+#endif
+
+
+/*
+ *
+ * SECTION 2
+ * INTERRUPT BASED ENTRY POINTS FOR THE TERMIOS MODULE
+ */
+
+/****************************************************************************
+* Func: SciInterruptOpen
+* Desc: open routine for the interrupt based device driver
+* Default state is 9600 baud, 8 bits, No parity, and 1 stop bit. ??
+**CHANGED** Default baud rate is now 19200, 8N1
+* called from rtems_termios_open which is called from console_open
+* Inputs: major - device number
+* minor - device number
+* args - points to terminal info
+* Outputs: success/fail
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+int SciInterruptOpen(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ rtems_libio_open_close_args_t * args = arg;
+ rtems_isr_entry old_vector;
+
+ if ( minor != SCI_MINOR ) /* check minor device num */
+ {
+ return -1;
+ }
+
+ if ( !args ) /* must have args */
+ {
+ return -1;
+ }
+
+ SciTermioTty = args->iop->data1; /* save address of struct */
+
+ SciDisableAllInterrupts(); /* turn off sci interrupts */
+
+ /* THIS IS ACTUALLY A BAD THING - SETTING LINE PARAMETERS HERE */
+ /* IT SHOULD BE DONE THROUGH TCSETATTR() WHEN THE CONSOLE IS OPENED!!! */
+
+/* SciSetBaud(115200); set the baud rate */
+/* SciSetBaud( 57600); set the baud rate */
+/* SciSetBaud( 38400); set the baud rate */
+/* SciSetBaud( 19200); set the baud rate */
+ SciSetBaud( 9600); /* set the baud rate */
+
+ SciSetParity(SCI_PARITY_NONE); /* set parity to none */
+
+ SciSetDataBits(SCI_8_DATA_BITS); /* set data bits to 8 */
+
+ /* Install our interrupt handler into RTEMS. */
+ /* 68 is an unused user-defined vector. Note that the vector must be */
+ /* even - it sets the low bit for SPI interrupts, and clears it for */
+ /* SCI interrupts. Also note that vector 66 is used by CPU32bug on */
+ /* the mrm332. */
+
+ rtems_interrupt_catch( SciIsr, 68, &old_vector );
+
+ *QSMCR = (*QSMCR & ~IARB) | 1; // Is 1 a good value for qsm iarb?
+ *QIVR = 68;
+ *QILR &= 0xf8;
+ *QILR |= 0x06 & 0x07;
+
+ SciEnableTransmitter(); /* enable the transmitter */
+
+ SciEnableReceiver(); /* enable the receiver */
+
+ SciEnableReceiveInterrupts(); /* enable rcv interrupts */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciInterruptClose
+* Desc: close routine called by the termios module
+* Inputs: major - device number
+* minor - device number
+* args - unused
+* Outputs: success/fail
+* Errors: none
+* Scope: public - termio entry point
+****************************************************************************/
+
+int SciInterruptClose(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ SciDisableAllInterrupts();
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciInterruptWrite
+* Desc: writes data to the uart using transmit interrupts
+* Inputs: minor - device number
+* buf - points to the data
+* len - number of bytes to send
+* Outputs: success/fail
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+ssize_t SciInterruptWrite(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ /* We are using interrupt driven output so termios only sends us */
+ /* one character at a time. The sci does not have a fifo. */
+
+ if ( !len ) /* no data? */
+ {
+ return -1; /* return error */
+ }
+
+ if ( minor != SCI_MINOR ) /* check the minor dev num */
+ {
+ return -1; /* return error */
+ }
+
+ if ( SciOpened == DRIVER_OPENED ) /* is the driver api open? */
+ {
+ return -1; /* yep, throw this away */
+ }
+
+ SciWriteCharNoWait(*buf); /* try to send a char */
+
+ *SCSR &= SCI_CLEAR_TDRE; /* clear tx data reg empty flag */
+
+ SciEnableTransmitInterrupts(); /* enable the tx interrupt */
+
+ return 0; /* return success */
+}
+
+
+/****************************************************************************
+* Func: SciSetAttributes
+* Desc: setup the uart based on the termios modules requests
+* Inputs: minor - device number
+* t - pointer to the termios info struct
+* Outputs: none
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+int SciSetAttributes(
+ int minor,
+ const struct termios *t
+)
+{
+ uint32_t baud_requested;
+ uint32_t sci_rate = 0;
+ uint16_t sci_parity = 0;
+ uint16_t sci_databits = 0;
+
+ if ( minor != SCI_MINOR ) /* check the minor dev num */
+ {
+ return -1; /* return error */
+ }
+
+ /* if you look closely you will see this is the only thing we use */
+ /* set the baud rate */
+
+ baud_requested = t->c_ospeed; /* baud rate */
+
+ if (!baud_requested)
+ {
+ baud_requested = B9600; /* default to 9600 baud */
+ /* baud_requested = B19200; default to 19200 baud */
+ }
+
+ sci_rate = rtems_termios_baud_to_number( baud_requested );
+
+ /* parity error detection */
+
+ if (t->c_cflag & PARENB) /* enable parity detection? */
+ {
+ if (t->c_cflag & PARODD)
+ {
+ sci_parity = SCI_PARITY_ODD; /* select odd parity */
+ }
+ else
+ {
+ sci_parity = SCI_PARITY_EVEN; /* select even parity */
+ }
+ }
+ else
+ {
+ sci_parity = SCI_PARITY_NONE; /* no parity, most common */
+ }
+
+ /* set the number of data bits, 8 is most common */
+
+ if (t->c_cflag & CSIZE) /* was it specified? */
+ {
+ switch (t->c_cflag & CSIZE)
+ {
+ case CS8: sci_databits = SCI_8_DATA_BITS; break;
+ default : sci_databits = SCI_9_DATA_BITS; break;
+ }
+ }
+ else
+ {
+ sci_databits = SCI_8_DATA_BITS; /* default to 8 data bits */
+ }
+
+ /* the number of stop bits; always 1 for SCI */
+
+ if (t->c_cflag & CSTOPB)
+ {
+ /* do nothing */
+ }
+
+ /* setup the hardware with these serial port parameters */
+
+ SciSetBaud(sci_rate); /* set the baud rate */
+ SciSetParity(sci_parity); /* set the parity type */
+ SciSetDataBits(sci_databits); /* set the data bits */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ *
+ * SECTION 3
+ * POLLING BASED ENTRY POINTS FOR THE TERMIOS MODULE
+ */
+
+/****************************************************************************
+* Func: SciPolledOpen
+* Desc: open routine for the polled i/o version of the driver
+* called from rtems_termios_open which is called from console_open
+* Inputs: major - device number
+* minor - device number
+* args - points to terminal info struct
+* Outputs: success/fail
+* Errors: none
+* Scope: public - termios entry point
+****************************************************************************/
+
+int SciPolledOpen(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ rtems_libio_open_close_args_t * args = arg;
+
+ if ( minor != SCI_MINOR ) /* check minor device num */
+ {
+ return -1;
+ }
+
+ if ( !args ) /* must have args */
+ {
+ return -1;
+ }
+
+ SciTermioTty = args->iop->data1; /* Store tty pointer */
+
+ SciDisableAllInterrupts(); /* don't generate interrupts */
+
+ /* THIS IS ACTUALLY A BAD THING - SETTING LINE PARAMETERS HERE */
+ /* IT SHOULD BE DONE THROUGH TCSETATTR() WHEN THE CONSOLE IS OPENED!!! */
+
+/* SciSetBaud(115200); set the baud rate */
+/* SciSetBaud( 57600); set the baud rate */
+/* SciSetBaud( 38400); set the baud rate */
+/* SciSetBaud( 19200); * set the baud rate */
+ SciSetBaud( 9600); /* set the baud rate */
+
+ SciSetParity(SCI_PARITY_NONE); /* set no parity */
+
+ SciSetDataBits(SCI_8_DATA_BITS); /* set 8 data bits */
+
+ SciEnableTransmitter(); /* enable the xmitter */
+
+ SciEnableReceiver(); /* enable the rcvr */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciPolledClose
+* Desc: close routine for the device driver, same for both
+* Inputs: major - device number
+* minor - device number
+* args - unused
+* Outputs: success/fail
+* Errors: none
+* Scope: public termios API
+****************************************************************************/
+
+int SciPolledClose(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ SciDisableAllInterrupts();
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciPolledRead
+* Desc: polling based read routine for the uart
+* Inputs: minor - device number
+* Outputs: error or the character read
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+int SciPolledRead(
+ int minor
+)
+{
+ if ( minor != SCI_MINOR ) /* check the type-punned dev num */
+ {
+ return -1; /* return error */
+ }
+
+ if ( SciCharAvailable() ) /* if a char is available */
+ {
+ return SciReadCharNoWait(); /* read the rx data register */
+ }
+
+ return -1; /* return error */
+}
+
+
+/****************************************************************************
+* Func: SciPolledWrite
+* Desc: writes out characters in polled mode, waiting for the uart
+* check in console_open, but we only seem to use interrupt mode
+* Inputs: minor - device number
+* buf - points to the data
+* len - how many bytes
+* Outputs: error or number of bytes written
+* Errors: none
+* Scope: public termios API
+****************************************************************************/
+
+ssize_t SciPolledWrite(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ ssize_t written = 0;
+
+ if ( minor != SCI_MINOR ) /* check minor device num */
+ {
+ return -1;
+ }
+
+ if ( SciOpened == DRIVER_OPENED ) /* is the driver api open? */
+ {
+ return -1; /* toss the data */
+ }
+
+ /* send each byte in the string out the port */
+
+ while ( written < len )
+ {
+ SciWriteCharWait(*buf++); /* send a byte */
+
+ written++; /* increment counter */
+ }
+
+ return written; /* return count */
+}
+
+
+/*
+ *
+ * SECTION 4
+ * DEVICE DRIVER PUBLIC API ENTRY POINTS
+ */
+
+/****************************************************************************
+* Func: SciInit
+* Desc: Initialize the lasers device driver and hardware
+* Inputs: major - the major device number which is assigned by rtems
+* minor - the minor device number which is undefined at this point
+* arg - ?????
+* Outputs: RTEMS_SUCCESSFUL
+* Errors: None.
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciInitialize (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+/* rtems_status_code status; */
+
+/*printk("%s\r\n", __FUNCTION__); */
+
+ /* register the SCI device name for termios console i/o
+ * this is done over in console.c which doesn't seem exactly right
+ * but there were problems doing it here...
+ */
+
+/* status = rtems_io_register_name( "/dev/sci", major, 0 ); */
+
+/* if (status != RTEMS_SUCCESSFUL) */
+/* rtems_fatal_error_occurred(status); */
+
+ SciMajor = major; /* save the rtems major number */
+
+ SciOpened = DRIVER_CLOSED; /* initial state is closed */
+
+ /* if you have an interrupt handler, install it here */
+
+ SciInited = 1; /* set the inited flag */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciOpen
+* Desc: device driver open routine
+* you must open a device before you can anything else
+* only one process can have the device opened at a time
+* you could look at the task id to restrict access if you want
+* Inputs: major - the major device number assigned by rtems
+* minor - the minor device number assigned by us
+* arg - ?????
+* Outputs: see below
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciOpen (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+/*printk("%s major=%d minor=%d\r\n", __FUNCTION__,major,minor); */
+
+ if (SciInited == 0) /* must be initialized first! */
+ {
+ return RTEMS_NOT_CONFIGURED;
+ }
+
+ if (minor != SCI_MINOR)
+ {
+ return RTEMS_INVALID_NAME; /* verify minor number */
+ }
+
+ if (SciOpened == DRIVER_OPENED)
+ {
+ return RTEMS_RESOURCE_IN_USE; /* already opened! */
+ }
+
+ SciOpened = DRIVER_OPENED; /* set the opened flag */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciClose
+* Desc: device driver close routine
+* the device must be opened before you can close it
+* the device must be closed before someone (else) can open it
+* Inputs: major - the major device number
+* minor - the minor device number
+* arg - ?????
+* Outputs: see below
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciClose (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+/*printk("%s major=%d minor=%d\r\n", __FUNCTION__,major,minor); */
+
+ if (minor != SCI_MINOR)
+ {
+ return RTEMS_INVALID_NAME; /* check the minor number */
+ }
+
+ if (SciOpened != DRIVER_OPENED)
+ {
+ return RTEMS_INCORRECT_STATE; /* must be opened first */
+ }
+
+ SciOpened = DRIVER_CLOSED; /* set the flag */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciRead
+* Desc: device driver read routine
+* this function is not meaningful for the laser devices
+* Inputs: major - the major device number
+* minor - the minor device number
+* arg - read/write arguments
+* Outputs: see below
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciRead (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_libio_rw_args_t *rw_args; /* ptr to argument struct */
+ char *buffer;
+
+ rw_args = (rtems_libio_rw_args_t *) arg; /* arguments to read() */
+
+ if (minor != SCI_MINOR)
+ {
+ return RTEMS_INVALID_NAME; /* check the minor number */
+ }
+
+ if (SciOpened == DRIVER_CLOSED)
+ {
+ return RTEMS_INCORRECT_STATE; /* must be opened first */
+ }
+
+ buffer = rw_args->buffer; /* points to user's buffer */
+
+/* *buffer = SciReadCharWait(); wait for a character */
+
+ /* if there isn't a character available, wait until one shows up */
+ /* or the timeout period expires, which ever happens first */
+
+ if ( SciRcvBufCount == 0 ) /* no chars */
+ {
+ /* wait for someone to wake me up... */
+ /*rtems_task_wake_after(SciReadTimeout); */
+ }
+
+ if ( SciRcvBufCount ) /* any characters locally? */
+ {
+ *buffer = SciRcvBufGetChar(); /* get the character */
+
+ rw_args->bytes_moved = 1; /* how many we actually read */
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciWrite
+* Desc: device driver write routine
+* this function is not meaningful for the laser devices
+* Inputs: major - the major device number
+* minor - the minor device number
+* arg - read/write arguments
+* Outputs: see below
+* Errors: non3
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciWrite (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_rw_args_t *rw_args; /* ptr to argument struct */
+ uint8_t *buffer;
+ size_t length;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ if (minor != SCI_MINOR)
+ {
+ return RTEMS_INVALID_NAME; /* check the minor number */
+ }
+
+ if (SciOpened == DRIVER_CLOSED)
+ {
+ return RTEMS_INCORRECT_STATE; /* must be opened first */
+ }
+
+ buffer = (uint8_t*)rw_args->buffer; /* points to data */
+
+ length = rw_args->count; /* how many bytes */
+
+ while (length--)
+ {
+ SciWriteCharWait(*buffer++); /* send the bytes out */
+ }
+
+ rw_args->bytes_moved = rw_args->count; /* how many we wrote */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciControl
+* Desc: device driver control routine
+* see below for an example of how to use the ioctl interface
+* Inputs: major - the major device number
+* minor - the minor device number
+* arg - io control args
+* Outputs: see below
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciControl (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_ioctl_args_t *args = arg; /* rtems arg struct */
+ uint16_t command; /* the cmd to execute */
+
+/*printk("%s major=%d minor=%d\r\n", __FUNCTION__,major,minor); */
+
+ /* do some sanity checking */
+
+ if (minor != SCI_MINOR)
+ {
+ return RTEMS_INVALID_NAME; /* check the minor number */
+ }
+
+ if (SciOpened == DRIVER_CLOSED)
+ {
+ return RTEMS_INCORRECT_STATE; /* must be open first */
+ }
+
+ if (args == 0)
+ {
+ return RTEMS_INVALID_ADDRESS; /* must have args */
+ }
+
+ args->ioctl_return = -1; /* assume an error */
+
+ command = args->command; /* get the command */
+
+ if (command == SCI_SEND_BREAK) /* process the command */
+ {
+ SciSendBreak(); /* send break char */
+ }
+
+ args->ioctl_return = 0; /* return status */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ *
+ * SECTION 5
+ * HARDWARE LEVEL ROUTINES
+ */
+
+/****************************************************************************
+* Func: SciSetBaud
+* Desc: setup the uart based on the termios modules requests
+* Inputs: baud rate
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void SciSetBaud(uint32_t rate)
+{
+ uint16_t value;
+ uint16_t save_sccr1;
+
+/* when you open the console you need to set the termio struct baud rate */
+/* it has a default value of 9600, when someone calls tcsetattr it reverts! */
+
+ SciBaud = rate; /* save the rate */
+
+ /* calculate the register value as a float and convert to an int */
+ /* set baud rate - you must define the system clock constant */
+ /* see mrm332.h for an example */
+
+ value = ( (uint16_t) ( SYS_CLOCK / rate / 32.0 + 0.5 ) & 0x1fff );
+
+ save_sccr1 = *SCCR1; /* save register */
+
+ /* also turns off the xmtr and rcvr */
+
+ *SCCR1 &= SCI_DISABLE_INT_ALL; /* disable interrupts */
+
+ *SCCR0 = value; /* write the register */
+
+ *SCCR1 = save_sccr1; /* restore register */
+
+ return;
+}
+
+
+/****************************************************************************
+* Func: SciSetParity
+* Desc: setup the uart based on the termios modules requests
+* Inputs: parity
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void SciSetParity(uint16_t parity)
+{
+ uint16_t value;
+
+ value = *SCCR1; /* get the register */
+
+ if (parity == SCI_PARITY_ODD)
+ {
+ value |= SCI_PARITY_ENABLE; /* parity enabled */
+ value |= SCI_PARITY_ODD; /* parity odd */
+ }
+
+ else if (parity == SCI_PARITY_EVEN)
+ {
+ value |= SCI_PARITY_ENABLE; /* parity enabled */
+ value &= ~SCI_PARITY_ODD; /* parity even */
+ }
+
+ else if (parity == SCI_PARITY_NONE)
+ {
+ value &= ~SCI_PARITY_ENABLE; /* disabled, most common */
+ }
+
+ /* else no changes */
+
+ *SCCR1 = value; /* write the register */
+
+ return;
+}
+
+
+/****************************************************************************
+* Func: SciSetDataBits
+* Desc: setup the uart based on the termios modules requests
+* Inputs: data bits
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void SciSetDataBits(uint16_t bits)
+{
+ uint16_t value;
+
+ value = *SCCR1; /* get the register */
+
+ /* note - the parity setting affects the number of data bits */
+
+ if (bits == SCI_9_DATA_BITS)
+ {
+ value |= SCI_9_DATA_BITS; /* 9 data bits */
+ }
+
+ else if (bits == SCI_8_DATA_BITS)
+ {
+ value &= SCI_8_DATA_BITS; /* 8 data bits */
+ }
+
+ /* else no changes */
+
+ *SCCR1 = value; /* write the register */
+
+ return;
+}
+
+
+/****************************************************************************
+* Func: SciDisableAllInterrupts
+* Func: SciEnableTransmitInterrupts
+* Func: SciEnableReceiveInterrupts
+* Desc: handles generation of interrupts by the sci module
+* Inputs: none
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void inline SciDisableAllInterrupts( void )
+{
+ /* this also turns off the xmtr and rcvr */
+
+ *SCCR1 &= SCI_DISABLE_INT_ALL;
+}
+
+static void inline SciEnableReceiveInterrupts( void )
+{
+ *SCCR1 |= SCI_ENABLE_INT_RX;
+}
+
+static void inline SciDisableReceiveInterrupts( void )
+{
+ *SCCR1 &= SCI_DISABLE_INT_RX;
+}
+
+static void inline SciEnableTransmitInterrupts( void )
+{
+ *SCCR1 |= SCI_ENABLE_INT_TX;
+}
+
+static void inline SciDisableTransmitInterrupts( void )
+{
+ *SCCR1 &= SCI_DISABLE_INT_TX;
+}
+
+
+/****************************************************************************
+* Func: SciEnableTransmitter, SciDisableTransmitter
+* Func: SciEnableReceiver, SciDisableReceiver
+* Desc: turns the transmitter and receiver on and off
+* Inputs: none
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void inline SciEnableTransmitter( void )
+{
+ *SCCR1 |= SCI_ENABLE_XMTR;
+}
+
+static void inline SciDisableTransmitter( void )
+{
+ *SCCR1 &= SCI_DISABLE_XMTR;
+}
+
+static void inline SciEnableReceiver( void )
+{
+ *SCCR1 |= SCI_ENABLE_RCVR;
+}
+
+static void inline SciDisableReceiver( void )
+{
+ *SCCR1 &= SCI_DISABLE_RCVR;
+}
+
+
+/****************************************************************************
+* Func: SciWriteCharWait
+* Desc: wait for room in the fifo and then put a char in
+* Inputs: a byte to send
+* Outputs: none
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+void SciWriteCharWait(uint8_t c)
+{
+ /* poll the fifo, waiting for room for another character */
+
+ while ( ( *SCSR & SCI_XMTR_AVAILABLE ) != SCI_XMTR_AVAILABLE )
+ {
+ /* Either we are writing to the fifo faster than
+ * the uart can clock bytes out onto the cable,
+ * or we are in flow control (actually no, we
+ * are ignoring flow control from the other end).
+ * In the first case, higher baud rates will help.
+ */
+ /* relinquish processor while waiting */
+ rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
+ }
+
+ *SCDR = c; /* send the charcter */
+
+ SciBytesOut++; /* increment the counter */
+
+ return;
+}
+
+/****************************************************************************
+* Func: SciWriteCharNoWait
+* Desc: if no room in the fifo throw the char on the floor
+* Inputs: a byte to send
+* Outputs: none
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+void SciWriteCharNoWait(uint8_t c)
+{
+ if ( ( *SCSR & SCI_XMTR_AVAILABLE ) == 0 )
+ {
+ return; /* no room, throw it away */
+ }
+
+ *SCDR = c; /* put the char in the fifo */
+
+ SciBytesOut++; /* increment the counter */
+
+ return;
+}
+
+
+/****************************************************************************
+* Func: SciReadCharWait
+* Desc: read a character, waiting for one to show up, if need be
+* Inputs: none
+* Outputs: a character
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+static uint8_t inline SciReadCharWait( void )
+{
+ uint8_t ch;
+
+ while ( SciCharAvailable() == 0 ) /* anything there? */
+ {
+ /* relinquish processor while waiting */
+ rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
+ }
+
+ /* if you have rcv ints enabled, then the isr will probably */
+ /* get the character before you will unless you turn off ints */
+ /* ie polling and ints don't mix that well */
+
+ ch = *SCDR; /* get the charcter */
+
+ SciBytesIn++; /* increment the counter */
+
+ return ch; /* return the char */
+}
+
+/****************************************************************************
+* Func: SciReadCharNoWait
+* Desc: try to get a char but dont wait for one
+* Inputs: none
+* Outputs: a character or -1 if none
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+static uint8_t inline SciReadCharNoWait( void )
+{
+ uint8_t ch;
+
+ if ( SciCharAvailable() == 0 ) /* anything there? */
+ return -1;
+
+ ch = *SCDR; /* get the character */
+
+ SciBytesIn++; /* increment the count */
+
+ return ch; /* return the char */
+}
+
+
+/****************************************************************************
+* Func: SciCharAvailable
+* Desc: is there a receive character in the data register
+* Inputs: none
+* Outputs: false if no char available, else true
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+uint8_t inline SciCharAvailable( void )
+{
+ return ( *SCSR & SCI_RCVR_READY ); /* char in data register? */
+}
+
+
+/****************************************************************************
+* Func: SciSendBreak
+* Desc: send 1 or tow breaks (all zero bits)
+* Inputs: none
+* Outputs: none
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+void SciSendBreak( void )
+{
+ /* From the Motorola QSM reference manual - */
+
+ /* "if SBK is toggled by writing it first to a one and then immediately */
+ /* to a zero (in less than one serial frame interval), the transmitter */
+ /* sends only one or two break frames before reverting to mark (idle) */
+ /* or before commencing to send more data" */
+
+ *SCCR1 |= SCI_SEND_BREAK; /* set the bit */
+
+ *SCCR1 &= ~SCI_SEND_BREAK; /* clear the bit */
+
+ return;
+}
+
+
+/*
+ *
+ * SECTION 6
+ * TEST CODE
+ */
+
+/****************************************************************************
+* Func: SciUnitTest
+* Desc: test the device driver
+* Inputs: nothing
+* Outputs: nothing
+* Scope: public
+****************************************************************************/
+
+#if 0
+void SciUnitTest()
+{
+ uint8_t byte; /* a character */
+ uint16_t fd; /* file descriptor for device */
+ uint16_t result; /* result of ioctl */
+
+ fd = open("/dev/sci",O_RDWR); /* open the device */
+
+printk("SCI open fd=%d\r\n",fd);
+
+ result = write(fd, "abcd\r\n", 6); /* send a string */
+
+printk("SCI write result=%d\r\n",result);
+
+ result = read(fd, &byte, 1); /* read a byte */
+
+printk("SCI read result=%d,byte=%x\r\n",result,byte);
+
+ return;
+}
+#endif
+
+
+/****************************************************************************
+* Func: SciPrintStats
+* Desc: print out some driver information
+* Inputs: nothing
+* Outputs: nothing
+* Scope: public
+****************************************************************************/
+
+void SciPrintStats ( void )
+{
+ printk("\r\n");
+
+ printk( "SYS_CLOCK is %2.6f Mhz\r\n\n", SYS_CLOCK / 1000000.0 );
+
+ printk( "Current baud rate is %d bps or %d cps\r\n\n", SciBaud, SciBaud / 10 );
+
+ printk( "SCI Uart chars in %8" PRIu32 "\r\n", SciBytesIn );
+ printk( "SCI Uart chars out %8" PRIu32 "\r\n", SciBytesOut );
+ printk( "SCI Uart framing errors %8" PRIu32 "\r\n", SciErrorsFraming );
+ printk( "SCI Uart parity errors %8" PRIu32 "\r\n", SciErrorsParity );
+ printk( "SCI Uart overrun errors %8" PRIu32 "\r\n", SciErrorsOverrun );
+ printk( "SCI Uart noise errors %8" PRIu32 "\r\n", SciErrorsNoise );
+
+ return;
+}