summaryrefslogtreecommitdiffstats
path: root/bsps/m68k/gen68340
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-19 06:28:01 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-20 13:08:32 +0200
commitd7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc (patch)
treecaa54b4229e86a68c84ab5961af34e087dce5302 /bsps/m68k/gen68340
parentbsps/powerpc: Move shared btimer support (diff)
downloadrtems-d7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc.tar.bz2
bsps: Move console drivers to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/m68k/gen68340')
-rw-r--r--bsps/m68k/gen68340/console/console.c690
-rw-r--r--bsps/m68k/gen68340/console/m340uart.c311
2 files changed, 1001 insertions, 0 deletions
diff --git a/bsps/m68k/gen68340/console/console.c b/bsps/m68k/gen68340/console/console.c
new file mode 100644
index 0000000000..d6634b1079
--- /dev/null
+++ b/bsps/m68k/gen68340/console/console.c
@@ -0,0 +1,690 @@
+/*
+ * 68340/68349 console serial I/O.
+ */
+
+/*
+ * Author:
+ * Geoffroy Montel
+ * France Telecom - CNET/DSM/TAM/CAT
+ * 4, rue du Clos Courtel
+ * 35512 CESSON-SEVIGNE
+ * FRANCE
+ *
+ * e-mail: g_montel@yahoo.com
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * 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 <termios.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <rtems/console.h>
+#include <m68340.h>
+#include <m340uart.h>
+#include <m340timer.h>
+
+#define CONSOLE_VECTOR 121
+#define CONSOLE_IRQ_LEVEL 3
+#define CONSOLE_INTERRUPT_ARBITRATION 2
+
+static void *ttypA; /* to remember which tty has been opened on channel A
+ used when interrupts are enabled */
+
+static void *ttypB; /* to remember which tty has been opened on channel B
+ used when interrupts are enabled */
+
+unsigned char DUIER_mirror = 0 ; /* reflects the state of IER register, which is Write Only */
+unsigned char Error_Status_A = 0; /* error status on Channel A */
+unsigned char Error_Status_B = 0; /* error status on Channel A */
+
+/*
+ * Device-specific routines
+ */
+
+#define USE_INTERRUPTS_A (m340_uart_config[UART_CHANNEL_A].mode==UART_INTERRUPTS)
+#define USE_INTERRUPTS_B (m340_uart_config[UART_CHANNEL_B].mode==UART_INTERRUPTS)
+#define CHANNEL_ENABLED_A m340_uart_config[UART_CHANNEL_A].enable
+#define CHANNEL_ENABLED_B m340_uart_config[UART_CHANNEL_B].enable
+
+#define set_DUIER(a) DUIER_mirror |= (a); DUIER = DUIER_mirror
+#define unset_DUIER(a) DUIER_mirror &= ~(a); DUIER = DUIER_mirror
+
+#define Enable_Interrupts_Tx_A if (USE_INTERRUPTS_A) set_DUIER(m340_TxRDYA)
+#define Disable_Interrupts_Tx_A if (USE_INTERRUPTS_A) unset_DUIER(m340_TxRDYA)
+
+#define Enable_Interrupts_Tx_B if (USE_INTERRUPTS_B) set_DUIER(m340_TxRDYB)
+#define Disable_Interrupts_Tx_B if (USE_INTERRUPTS_B) unset_DUIER(m340_TxRDYB)
+
+/******************************************************
+ Name: InterruptHandler
+ Input parameters: vector number
+ Output parameters: -
+ Description: UART ISR Routine, called by _RTEMS_ISR
+ *****************************************************/
+rtems_isr
+InterruptHandler (rtems_vector_number v)
+{
+ char ch;
+
+ /*****************************************************************************
+ ** CHANNEL A **
+ *****************************************************************************/
+
+ /* check Received Break*/
+ if (DUSRA & m340_RB) {
+ Error_Status_A |= m340_RB;
+ /* reset error status */
+ DUCRA = m340_Reset_Error_Status;
+ }
+
+ /* buffer received ? */
+ if (DUSRA & m340_Rx_RDY) {
+ do {
+ /* error encountered? */
+ if (DUSRA & (m340_OE | m340_PE | m340_FE | m340_RB)) {
+ Error_Status_A |= DUSRA;
+ /* reset error status */
+ DUCRA = m340_Reset_Error_Status;
+ /* all the characters in the queue may not be good */
+ while (DUSRA & m340_Rx_RDY)
+ /* push them in a trash */
+ ch = DURBA;
+ }
+ else {
+ /* this is necessary, otherwise it blocks when FIFO is full */
+ ch = DURBA;
+ rtems_termios_enqueue_raw_characters(ttypA,&ch,1);
+ }
+ } while (DUSRA & m340_Rx_RDY);
+ Restart_Fifo_Full_A_Timer(); /* only if necessary (pointer to a fake function if
+ not in FIFO full mode) */
+ }
+
+ else /* if no character has been received */
+ Restart_Check_A_Timer(); /* same remark */
+
+ /* ready to accept a character ? */
+ if (DUISR & DUIER_mirror & m340_TxRDYA) {
+ Disable_Interrupts_Tx_A;
+ /* one character has been transmitted */
+ rtems_termios_dequeue_characters(ttypA,1);
+ }
+
+ /*****************************************************************************
+ ** CHANNEL B **
+ *****************************************************************************/
+
+ /* check Received Break*/
+ if (DUSRB & m340_RB) {
+ Error_Status_B |= m340_RB;
+ /* reset error status */
+ DUCRB = m340_Reset_Error_Status;
+ }
+
+ /* buffer received ? */
+ if (DUSRB & m340_Rx_RDY) {
+ do {
+ if (DUSRB & (m340_OE | m340_PE | m340_FE | m340_RB)) {
+ Error_Status_B |= DUSRB;
+ /* reset error status */
+ DUCRB = m340_Reset_Error_Status;
+ /* all the characters in the queue may not be good */
+ while (DUSRB & m340_Rx_RDY)
+ /* push them in a trash */
+ ch = DURBB;
+ }
+ else {
+ ch = DURBB;
+ rtems_termios_enqueue_raw_characters(ttypB,&ch,1);
+ }
+
+ } while (DUSRB & m340_Rx_RDY);
+ Restart_Fifo_Full_B_Timer();
+ }
+ else /* if no character has been received */
+ Restart_Check_B_Timer();
+
+ /* ready to accept a character ? */
+ if (DUISR & DUIER_mirror & m340_TxRDYB) {
+ Disable_Interrupts_Tx_B;
+ /* one character has been transmitted */
+ rtems_termios_dequeue_characters(ttypB,1);
+ }
+}
+
+/******************************************************
+ Name: InterruptWrite
+ Input parameters: minor = channel, pointer to buffer,
+ and length of buffer to transmit
+ Output parameters: -
+ Description: write the first character of buf only
+ may be called by either console_write
+ or rtems_termios_enqueue_raw_characters
+ *****************************************************/
+static ssize_t
+InterruptWrite (int minor, const char *buf, size_t len)
+{
+ if (minor==UART_CHANNEL_A) {
+ if (len>0) {
+ DUTBA=*buf;
+ Enable_Interrupts_Tx_A;
+ }
+ }
+ else if (minor==UART_CHANNEL_B) {
+ if (len>0) {
+ DUTBB=*buf;
+ Enable_Interrupts_Tx_B;
+ }
+ }
+ return 0;
+}
+
+/******************************************************
+ Name: dbug_out_char
+ Input parameters: channel, character to emit
+ Output parameters: -
+ Description: wait for the UART to be ready to emit
+ a character and send it
+ *****************************************************/
+void dbug_out_char( int minor, int ch )
+{
+ if (minor==UART_CHANNEL_A) {
+ while (!(DUSRA & m340_Tx_RDY)) continue;
+ DUTBA=ch;
+ }
+ else if (minor==UART_CHANNEL_B) {
+ while (!(DUSRB & m340_Tx_RDY)) continue;
+ DUTBB=ch;
+ }
+}
+
+/******************************************************
+ Name: dbug_in_char
+ Input parameters: -
+ Output parameters: received character
+ Description: return the character in the UART
+ *****************************************************/
+int dbug_in_char( int minor )
+{
+ if (minor==UART_CHANNEL_A) {
+ return DURBA;
+ }
+ else if (minor==UART_CHANNEL_B) {
+ return DURBB;
+ }
+ return 0;
+}
+
+/******************************************************
+ Name: dbug_char_present
+ Input parameters: channel #
+ Output parameters: TRUE or FALSE
+ Description: return whether there's a character
+ in the receive buffer
+ *****************************************************/
+int dbug_char_present( int minor )
+{
+ if (minor==UART_CHANNEL_A) {
+ return (DUSRA & m340_Rx_RDY);
+ }
+ else if (minor==UART_CHANNEL_B) {
+ return (DUSRB & m340_Rx_RDY);
+ }
+ return 0;
+}
+
+/******************************************************
+ Name: dbugInitialise
+ Input parameters: -
+ Output parameters: -
+ Description: Init the UART
+ *****************************************************/
+static void
+dbugInitialise (void)
+{
+ t_baud_speed_table uart_config; /* configuration of UARTS */
+
+ /*
+ * Reset Receiver
+ */
+ DUCRA = m340_Reset_Receiver;
+ DUCRB = m340_Reset_Receiver;
+
+ /*
+ * Reset Transmitter
+ */
+ DUCRA = m340_Reset_Transmitter;
+ DUCRB = m340_Reset_Transmitter;
+
+ /*
+ * Enable serial module for normal operation, ignore FREEZE, select the crystal clock,
+ * supervisor/user serial registers unrestricted
+ * interrupt arbitration at priority CONSOLE_INTERRUPT_ARBITRATION
+ * WARNING : 8 bits access only on this UART!
+ */
+ DUMCRH = 0x00;
+ DUMCRL = CONSOLE_INTERRUPT_ARBITRATION;
+
+ /*
+ * Interrupt level register
+ */
+ DUILR = CONSOLE_IRQ_LEVEL;
+
+ /* sets the IVR */
+ DUIVR = CONSOLE_VECTOR;
+
+ /* search for a correct m340 uart configuration */
+ uart_config = Find_Right_m340_UART_Config(m340_uart_config[UART_CHANNEL_A].rx_baudrate,
+ m340_uart_config[UART_CHANNEL_A].tx_baudrate,
+ CHANNEL_ENABLED_A,
+ m340_uart_config[UART_CHANNEL_B].rx_baudrate,
+ m340_uart_config[UART_CHANNEL_B].tx_baudrate,
+ CHANNEL_ENABLED_B);
+
+ /*****************************************************************************
+ ** CHANNEL A **
+ *****************************************************************************/
+ if (CHANNEL_ENABLED_A) {
+
+ if (USE_INTERRUPTS_A) {
+ rtems_isr_entry old_handler;
+
+ (void) rtems_interrupt_catch (InterruptHandler,
+ CONSOLE_VECTOR,
+ &old_handler);
+
+ /* uncomment this if you want to pass control to your own ISR handler
+ it may be usefull to do so to check for performances with an oscilloscope */
+ /*
+ {
+ proc_ptr ignored;
+ _CPU_ISR_install_raw_handler( CONSOLE_VECTOR, _Debug_ISR_Handler_Console, &ignored );
+ }
+ */
+
+ /*
+ * Interrupt Enable Register
+ * Enable Interrupts on Channel A Receiver Ready
+ */
+ set_DUIER(m340_RxRDYA);
+ }
+ else {
+ /*
+ * Disable Interrupts on channel A
+ */
+ unset_DUIER(m340_RxRDYA&m340_TxRDYA);
+ }
+
+ /*
+ * Change set of baud speeds
+ * disable input control
+ */
+ /* no good uart configuration ? */
+ if (uart_config.nb<1) rtems_fatal_error_occurred (-1);
+
+ if (uart_config.baud_speed_table[UART_CHANNEL_A].set==1)
+ DUACR = m340_BRG_Set1;
+ else
+ DUACR = m340_BRG_Set2;
+
+ /*
+ * make OPCR an auxiliary function serving the communication channels
+ */
+ DUOPCR = m340_OPCR_Aux;
+
+ /* poll the XTAL_RDY bit until it is cleared to ensure that an unstable crystal
+ input is not applied to the baud rate generator */
+ while (DUISR & m340_XTAL_RDY) continue;
+
+ /*
+ * Serial Channel Baud Speed
+ */
+ DUCSRA = (uart_config.baud_speed_table[UART_CHANNEL_A].rcs << 4)
+ | (uart_config.baud_speed_table[UART_CHANNEL_A].tcs);
+
+ /*
+ * Serial Channel Configuration
+ */
+ DUMR1A = m340_uart_config[UART_CHANNEL_A].parity_mode
+ | m340_uart_config[UART_CHANNEL_A].bits_per_char
+ | m340_RxRTS;
+
+ if (m340_uart_config[UART_CHANNEL_A].rx_mode==UART_FIFO_FULL) DUMR1A |= m340_R_F | m340_ERR;
+
+ /*
+ * Serial Channel Configuration 2
+ */
+ DUMR2A |= m340_normal;
+
+ /*
+ * Enable Channel A: transmitter and receiver
+ */
+ DUCRA = m340_Transmitter_Enable | m340_Receiver_Enable;
+ } /* channel A enabled */
+
+ /*****************************************************************************
+ ** CHANNEL B **
+ *****************************************************************************/
+ if (CHANNEL_ENABLED_B) {
+
+ /* we mustn't set the console vector twice! */
+ if ((USE_INTERRUPTS_B && !(CHANNEL_ENABLED_A))
+ || (USE_INTERRUPTS_B && CHANNEL_ENABLED_A && !USE_INTERRUPTS_A)) {
+ rtems_isr_entry old_handler;
+
+ (void) rtems_interrupt_catch (InterruptHandler,
+ CONSOLE_VECTOR,
+ &old_handler);
+
+ /* uncomment this if you want to pass control to your own ISR handler
+ it may be usefull to do so to check for performances with an oscilloscope */
+ /*
+ {
+ proc_ptr ignored;
+ _CPU_ISR_install_raw_handler( CONSOLE_VECTOR, _Debug_ISR_Handler_Console, &ignored );
+ }
+ */
+
+ /*
+ * Interrupt Enable Register
+ * Enable Interrupts on Channel A Receiver Ready
+ */
+ set_DUIER(m340_RxRDYB);
+ }
+ else {
+ /*
+ * Disable Interrupts on channel B
+ */
+ unset_DUIER(m340_RxRDYB&m340_TxRDYB);
+ }
+
+ /*
+ * Change set of baud speeds
+ * disable input control
+ */
+
+ /* no good uart configuration ? */
+ if (uart_config.nb<2) rtems_fatal_error_occurred (-1);
+
+ /* don't set DUACR twice! */
+ if (!CHANNEL_ENABLED_A) {
+ if (uart_config.baud_speed_table[UART_CHANNEL_B].set==1)
+ DUACR = m340_BRG_Set1;
+ else
+ DUACR = m340_BRG_Set2;
+ }
+
+ /*
+ * make OPCR an auxiliary function serving the communication channels
+ */
+ if (!CHANNEL_ENABLED_A) DUOPCR = m340_OPCR_Aux;
+
+ /* poll the XTAL_RDY bit until it is cleared to ensure that an unstable crystal
+ input is not applied to the baud rate generator */
+ while (DUISR & m340_XTAL_RDY) continue;
+
+ /*
+ * Serial Channel Baud Speed
+ */
+ DUCSRB = (uart_config.baud_speed_table[UART_CHANNEL_B].rcs << 4)
+ | (uart_config.baud_speed_table[UART_CHANNEL_B].tcs);
+
+ /*
+ * Serial Channel Configuration
+ */
+ DUMR1B = m340_uart_config[UART_CHANNEL_B].parity_mode
+ | m340_uart_config[UART_CHANNEL_B].bits_per_char
+ | m340_RxRTS;
+
+ if (m340_uart_config[UART_CHANNEL_B].rx_mode==UART_FIFO_FULL) DUMR1B |= m340_R_F | m340_ERR;
+
+ /*
+ * Serial Channel Configuration 2
+ */
+ DUMR2B |= m340_normal;
+
+ /*
+ * Enable Channel A: transmitter and receiver
+ */
+ DUCRB = m340_Transmitter_Enable | m340_Receiver_Enable;
+ } /* channel B enabled */
+}
+
+/******************************************************
+ Name: SetAttributes
+ Input parameters: termios structure, channel
+ Output parameters: -
+ Description: return whether there's a character
+ in the receive buffer
+ TO DO: add the channel # to check for!!
+ *****************************************************/
+static int
+SetAttributes (int minor, const struct termios *t)
+{
+ rtems_interrupt_level level;
+ float ispeed, ospeed;
+
+ /* convert it */
+ ispeed = rtems_termios_baud_to_number(t->c_ispeed);
+ ospeed = rtems_termios_baud_to_number(t->c_ospeed);
+
+ if (ispeed || ospeed) {
+ /* update config table */
+ m340_uart_config[UART_CHANNEL_A].rx_baudrate = ((minor==UART_CHANNEL_A)&&(ispeed!=0)) ? ispeed : m340_uart_config[UART_CHANNEL_A].rx_baudrate;
+ m340_uart_config[UART_CHANNEL_A].tx_baudrate = ((minor==UART_CHANNEL_A)&&(ospeed!=0)) ? ospeed : m340_uart_config[UART_CHANNEL_A].tx_baudrate;
+ m340_uart_config[UART_CHANNEL_B].rx_baudrate = ((minor==UART_CHANNEL_B)&&(ispeed!=0)) ? ispeed : m340_uart_config[UART_CHANNEL_B].rx_baudrate;
+ m340_uart_config[UART_CHANNEL_B].tx_baudrate = ((minor==UART_CHANNEL_B)&&(ospeed!=0)) ? ospeed : m340_uart_config[UART_CHANNEL_B].tx_baudrate;
+ }
+
+ /* change parity */
+ if (t->c_cflag & PARENB) {
+ if (t->c_cflag & PARODD) m340_uart_config[minor].parity_mode = m340_Odd_Parity;
+ else m340_uart_config[minor].parity_mode = m340_Even_Parity;
+ }
+
+ /* change bits per character */
+ if (t->c_cflag & CSIZE) {
+ switch (t->c_cflag & CSIZE) {
+ default: break;
+ case CS5: m340_uart_config[minor].bits_per_char = m340_5bpc; break;
+ case CS6: m340_uart_config[minor].bits_per_char = m340_6bpc; break;
+ case CS7: m340_uart_config[minor].bits_per_char = m340_7bpc; break;
+ case CS8: m340_uart_config[minor].bits_per_char = m340_8bpc; break;
+ }
+ }
+
+ /* if serial module configuration has been changed */
+ if (t->c_cflag & (CSIZE | PARENB)) {
+ rtems_interrupt_disable(level);
+ /* reinit the UART */
+ dbugInitialise();
+ rtems_interrupt_enable (level);
+ }
+
+ return 0;
+}
+
+/******************************************************
+ Name: console_initialize
+ Input parameters: MAJOR # of console_driver,
+ minor is always 0,
+ args are always NULL
+ Output parameters: -
+ Description: Reserve resources consumed by this driver
+ TODO: We should pass m340_uart_config table in arg
+ *****************************************************/
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_status_code status;
+ int i;
+
+ /*
+ * Set up TERMIOS
+ */
+ rtems_termios_initialize ();
+
+ /*
+ * Do device-specific initialization
+ */
+ Init_UART_Table();
+ dbugInitialise ();
+ Fifo_Full_benchmark_timer_initialize();
+
+ /*
+ * Register the devices
+ */
+ for (i=0; i<UART_NUMBER_OF_CHANNELS; i++) {
+ if (m340_uart_config[i].enable) {
+ status = rtems_io_register_name (m340_uart_config[i].name, major, i);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+ }
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/******************************************************
+ Name: console_open
+ Input parameters: channel #, arg
+ Output parameters: -
+ Description: open the device
+ *****************************************************/
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_status_code sc = 0;
+
+ static const rtems_termios_callbacks intrCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ NULL, /* pollRead */
+ InterruptWrite, /* write */
+ SetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 1 /* outputUsesInterrupts */
+ };
+
+ static const rtems_termios_callbacks pollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ dbugRead, /* pollRead */
+ dbugWrite, /* write */
+ SetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 0 /* outputUsesInterrupts */
+ };
+
+ if (minor==UART_CHANNEL_A) {
+ if (USE_INTERRUPTS_A) {
+ rtems_libio_open_close_args_t *args = arg;
+
+ sc |= rtems_termios_open (major, minor, arg, &intrCallbacks);
+ ttypA = args->iop->data1;
+ }
+ else {
+ sc |= rtems_termios_open (major, minor, arg, &pollCallbacks);
+ }
+ }
+
+ else if (minor==UART_CHANNEL_B) {
+ if (USE_INTERRUPTS_B) {
+ rtems_libio_open_close_args_t *args = arg;
+
+ sc |= rtems_termios_open (major, minor, arg, &intrCallbacks);
+ ttypB = args->iop->data1;
+ }
+ else {
+ sc |= rtems_termios_open (major, minor, arg, &pollCallbacks);
+ }
+ }
+
+ else return RTEMS_INVALID_NUMBER;
+
+ return sc;
+}
+
+/******************************************************
+ Name: console_close
+ Input parameters: channel #, termios args
+ Output parameters: -
+ Description: close the device
+ *****************************************************/
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_close (arg);
+}
+
+/******************************************************
+ Name: console_read
+ Input parameters: channel #, termios args
+ Output parameters: -
+ Description: read the device
+ *****************************************************/
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_read (arg);
+}
+
+/******************************************************
+ Name: console_write
+ Input parameters: channel #, termios args
+ Output parameters: -
+ Description: write to the device
+ *****************************************************/
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_write (arg);
+}
+
+/******************************************************
+ Name: console_control
+ Input parameters: channel #, termios args
+ Output parameters: -
+ Description: Handle ioctl request
+ *****************************************************/
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_ioctl_args_t *args = arg;
+
+ if (args->command == TIOCSETA)
+ SetAttributes (minor, (struct termios *)args->buffer);
+
+ return rtems_termios_ioctl (arg);
+}
diff --git a/bsps/m68k/gen68340/console/m340uart.c b/bsps/m68k/gen68340/console/m340uart.c
new file mode 100644
index 0000000000..56ad29c256
--- /dev/null
+++ b/bsps/m68k/gen68340/console/m340uart.c
@@ -0,0 +1,311 @@
+/*
+ * M68340/349 UART management tools
+ */
+
+/*
+ * Author:
+ * Geoffroy Montel
+ * France Telecom - CNET/DSM/TAM/CAT
+ * 4, rue du Clos Courtel
+ * 35512 CESSON-SEVIGNE
+ * FRANCE
+ *
+ * e-mail: g_montel@yahoo.com
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * 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 <termios.h>
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <m68340.h>
+#include <m340uart.h>
+#include <stdarg.h>
+#include <string.h>
+
+/* this table shows compatible speed configurations for the MC68340:
+ the first row shows baud rates for baud speed set 1
+ the second row shows baud rates for baud speed set 2
+ look at Motorola's MC68340 Integrated Processor User's Manual
+ page 7-30 for more infos */
+
+float m340_Baud_Rates_Table[16][2] = {
+ { 50, 75 },
+ { 110, 110 },
+ { 134.5, 134.5 },
+ { 200, 150 },
+ { 300, 300 },
+ { 600, 600 },
+ { 1200, 1200 },
+ { 1050, 2000 },
+ { 2400, 2400 },
+ { 4800, 4800 },
+ { 7200, 1800 },
+ { 9600, 9600 },
+ { 38400, 19200 },
+ { 76800, 38400 },
+ { SCLK/16, SCLK/16},
+ { SCLK, SCLK },
+};
+
+/* config on both 340 channels */
+uart_channel_config m340_uart_config[UART_NUMBER_OF_CHANNELS];
+
+/*
+ * Init UART table
+ */
+
+#define NOT_IMPLEMENTED_YET 0
+
+/******************************************************
+ Name: Init_UART_Table
+ Input parameters: -
+ Output parameters: -
+ Description: Init the m340_uart_config
+ THIS SHOULD NOT BE HERE!
+ Its aim was to let the user configure
+ UARTs for each application.
+ As we can't pass args to the console
+ driver initialisation routine at the
+ moment, this was not done.
+ ATTENTION: TERMIOS init presupposes that the channel
+ baud rates is 9600/9600.
+ -> risks when using IOCTL
+ *****************************************************/
+void Init_UART_Table(void)
+{
+ m340_uart_config[UART_CHANNEL_A].enable = TRUE;
+ strcpy(m340_uart_config[UART_CHANNEL_A].name, UART_CONSOLE_NAME);
+ m340_uart_config[UART_CHANNEL_A].parity_mode = m340_No_Parity;
+ m340_uart_config[UART_CHANNEL_A].bits_per_char = m340_8bpc;
+ m340_uart_config[UART_CHANNEL_A].rx_baudrate = 9600;
+ m340_uart_config[UART_CHANNEL_A].tx_baudrate = 9600;
+ m340_uart_config[UART_CHANNEL_A].rx_mode = UART_CRR;
+ m340_uart_config[UART_CHANNEL_A].mode = UART_POLLING;
+
+ m340_uart_config[UART_CHANNEL_A].termios.enable = TRUE;
+ m340_uart_config[UART_CHANNEL_A].termios.rx_buffer_size = NOT_IMPLEMENTED_YET;
+ m340_uart_config[UART_CHANNEL_A].termios.tx_buffer_size = NOT_IMPLEMENTED_YET;
+
+ m340_uart_config[UART_CHANNEL_B].enable = FALSE;
+ strcpy(m340_uart_config[UART_CHANNEL_B].name, UART_RAW_IO_NAME);
+ m340_uart_config[UART_CHANNEL_B].parity_mode = m340_No_Parity;
+ m340_uart_config[UART_CHANNEL_B].bits_per_char = m340_8bpc;
+ m340_uart_config[UART_CHANNEL_B].rx_baudrate = 38400;
+ m340_uart_config[UART_CHANNEL_B].tx_baudrate = 38400;
+ m340_uart_config[UART_CHANNEL_B].rx_mode = UART_CRR;
+ m340_uart_config[UART_CHANNEL_B].mode = UART_INTERRUPTS;
+
+ m340_uart_config[UART_CHANNEL_B].termios.enable = TRUE;
+ m340_uart_config[UART_CHANNEL_B].termios.rx_buffer_size = NOT_IMPLEMENTED_YET;
+ m340_uart_config[UART_CHANNEL_B].termios.tx_buffer_size = NOT_IMPLEMENTED_YET;
+}
+
+/******************************************************
+ Name: Find_Right_m340_UART_Channel_Config
+ Input parameters: Send/Receive baud rates for a
+ given channel
+ Output parameters: UART compatible configs for this
+ channel
+ Description: returns which uart configurations fit
+ Receiver Baud Rate and Transmitter Baud
+ Rate for a given channel
+ For instance, according to the
+ m340_Baud_Rates_Table:
+ - Output Speed = 50, Input Speed = 75
+ is not a correct config, because
+ 50 bauds implies set 1 and 75 bauds
+ implies set 2
+ - Output Speed = 9600, Input Speed = 9600
+ two correct configs for this:
+ RCS=11, TCS=11, Set=1 or 2
+ *****************************************************/
+static t_baud_speed_table
+Find_Right_m340_UART_Channel_Config(
+ float ReceiverBaudRate,
+ float TransmitterBaudRate
+)
+{
+ t_baud_speed_table return_value;
+ int i,j;
+
+ struct {
+ int cs;
+ int set;
+ } Receiver[2], Transmitter[2];
+
+ int Receiver_nb_of_config = 0;
+ int Transmitter_nb_of_config = 0;
+
+ /* Receiver and Transmitter baud rates must be compatible, ie in the
+ * same set.
+ */
+
+ /* search for configurations for ReceiverBaudRate
+ * there can't be more than two (only two sets).
+ */
+ for (i=0;i<16;i++) {
+ for (j=0;j<2;j++) {
+ if (m340_Baud_Rates_Table[i][j]==ReceiverBaudRate) {
+ Receiver[Receiver_nb_of_config].cs=i;
+ Receiver[Receiver_nb_of_config].set=j;
+ Receiver_nb_of_config++;
+ }
+ }
+ }
+
+ /* search for configurations for TransmitterBaudRate
+ * there can't be more than two (only two sets)
+ */
+ for (i=0;i<16;i++) {
+ for (j=0;j<2;j++) {
+ if (m340_Baud_Rates_Table[i][j]==TransmitterBaudRate) {
+ Transmitter[Transmitter_nb_of_config].cs=i;
+ Transmitter[Transmitter_nb_of_config].set=j;
+ Transmitter_nb_of_config++;
+ }
+ }
+ }
+
+ /* now check if there's a compatible config */
+ return_value.nb=0;
+
+ for (i=0; i<Receiver_nb_of_config; i++) {
+ for (j=0;j<Transmitter_nb_of_config;j++) {
+ if (Receiver[i].set == Transmitter[j].set) {
+ return_value.baud_speed_table[return_value.nb].set = Receiver[i].set + 1;
+ /* we want set 1 or set 2, not 0 or 1 */
+ return_value.baud_speed_table[return_value.nb].rcs = Receiver[i].cs;
+ return_value.baud_speed_table[return_value.nb].tcs = Transmitter[j].cs;
+ return_value.nb++;
+ }
+ }
+ }
+
+ return return_value;
+}
+
+/******************************************************
+ Name: Find_Right_m340_UART_Config
+ Input parameters: Send/Receive baud rates for both
+ channels
+ Output parameters: UART compatible configs for
+ BOTH channels
+ Description: returns which uart configurations fit
+ Receiver Baud Rate and Transmitter Baud
+ Rate for both channels
+ For instance, if we want 9600/38400 on
+ channel A and 9600/19200 on channel B,
+ this is not a good m340 uart config
+ (channel A needs set 1 and channel B
+ needs set 2)
+ *****************************************************/
+t_baud_speed_table
+Find_Right_m340_UART_Config(
+ float ChannelA_ReceiverBaudRate,
+ float ChannelA_TransmitterBaudRate,
+ uint8_t enableA,
+ float ChannelB_ReceiverBaudRate,
+ float ChannelB_TransmitterBaudRate,
+ uint8_t enableB
+)
+{
+ t_baud_speed_table tableA, tableB;
+ t_baud_speed_table return_value, tmp;
+ int i,j;
+
+ memset( &return_value, '\0', sizeof(return_value) );
+ return_value.nb=0;
+
+ if (enableA && enableB) {
+ tableA = Find_Right_m340_UART_Channel_Config(
+ ChannelA_ReceiverBaudRate, ChannelA_TransmitterBaudRate);
+ tableB = Find_Right_m340_UART_Channel_Config(
+ ChannelB_ReceiverBaudRate, ChannelB_TransmitterBaudRate);
+
+ for (i=0;i<tableA.nb;i++) {
+ for (j=0;j<tableB.nb;j++) {
+ if (tableA.baud_speed_table[i].set==tableB.baud_speed_table[j].set) {
+ return_value.baud_speed_table[UART_CHANNEL_A].set =
+ tableA.baud_speed_table[i].set;
+ return_value.baud_speed_table[UART_CHANNEL_A].rcs =
+ tableA.baud_speed_table[i].rcs;
+ return_value.baud_speed_table[UART_CHANNEL_A].tcs =
+ tableA.baud_speed_table[i].tcs;
+ return_value.baud_speed_table[UART_CHANNEL_B].set =
+ tableB.baud_speed_table[j].set;
+ return_value.baud_speed_table[UART_CHANNEL_B].rcs =
+ tableB.baud_speed_table[j].rcs;
+ return_value.baud_speed_table[UART_CHANNEL_B].tcs =
+ tableB.baud_speed_table[j].tcs;
+ return_value.nb=2;
+ break;
+ }
+ }
+ }
+ return return_value;
+ }
+
+ if (enableA) {
+ return_value = Find_Right_m340_UART_Channel_Config(
+ ChannelA_ReceiverBaudRate, ChannelA_TransmitterBaudRate);
+ return return_value;
+ }
+
+ if (enableB) {
+ tmp = Find_Right_m340_UART_Channel_Config(
+ ChannelB_ReceiverBaudRate, ChannelB_TransmitterBaudRate);
+ if (tmp.nb!=0) {
+ return_value.nb = 2;
+ return_value.baud_speed_table[1].set = tmp.baud_speed_table[0].set;
+ return_value.baud_speed_table[1].rcs = tmp.baud_speed_table[0].rcs;
+ return_value.baud_speed_table[1].tcs = tmp.baud_speed_table[0].tcs;
+ }
+ }
+ return return_value;
+}
+
+
+/*
+ * very low level fmted output
+ */
+extern void dbug_out_char( int minor, int ch );
+extern int dbug_in_char( int minor );
+extern int dbug_char_present( int minor );
+
+/******************************************************
+ Name: dbugRead
+ Input parameters: channel
+ Output parameters: char read
+ Description: polled read
+ *****************************************************/
+int dbugRead (int minor)
+{
+ if (dbug_char_present(minor) == 0)
+ return -1;
+ return dbug_in_char(minor);
+}
+
+/******************************************************
+ Name: dbugWrite
+ Input parameters: channel, buffer and its length
+ Output parameters: always successfull
+ Description: polled write
+ *****************************************************/
+ssize_t dbugWrite (int minor, const char *buf, size_t len)
+{
+ static char txBuf;
+ size_t retval = len;
+
+ while (len--) {
+ txBuf = *buf++;
+ dbug_out_char( minor, (int)txBuf );
+ }
+ return retval;
+}
+