summaryrefslogtreecommitdiffstats
path: root/bsps/m68k/gen68360/console/console.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/m68k/gen68360/console/console.c')
-rw-r--r--bsps/m68k/gen68360/console/console.c390
1 files changed, 390 insertions, 0 deletions
diff --git a/bsps/m68k/gen68360/console/console.c b/bsps/m68k/gen68360/console/console.c
new file mode 100644
index 0000000000..36d8470168
--- /dev/null
+++ b/bsps/m68k/gen68360/console/console.c
@@ -0,0 +1,390 @@
+/*
+ * SMC1 raw console serial I/O.
+ *
+ * This driver is an example of `POLLING' or `INTERRUPT' I/O.
+ *
+ * To run with interrupt-driven I/O, ensure m360_smc1_interrupt
+ * is set before calling the initialization routine.
+ */
+
+/*
+ * Author:
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ *
+ * 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 <rtems/console.h>
+#include <rtems/termiostypes.h>
+#include <rtems/m68k/m68360.h>
+
+/*
+ * Declare clock speed -- may be overwritten by downloader or debugger
+ */
+int m360_clock_rate = 25000000;
+
+/*
+ * Interrupt-driven input buffer
+ * Declare console baud rate -- may also be overwritten
+ */
+int console_baud_rate = 9600;
+
+/*
+ */
+#define RXBUFSIZE 16
+
+/*
+ * Interrupt-driven callback
+ */
+static int m360_smc1_interrupt = 1;
+static void *smc1ttyp;
+
+/*
+ * I/O buffers and pointers to buffer descriptors
+ */
+static volatile char rxBuf[RXBUFSIZE];
+static volatile m360BufferDescriptor_t *smcRxBd, *smcTxBd;
+
+/*
+ * Device-specific routines
+ */
+
+/*
+ * Compute baud-rate-generator configuration register value
+ */
+static int
+smc1BRGC (int baud)
+{
+ int divisor;
+ int div16 = 0;
+
+ divisor = ((m360_clock_rate / 16) + (baud / 2)) / baud;
+ if (divisor > 4096) {
+ div16 = 1;
+ divisor = (divisor + 8) / 16;
+ }
+ return M360_BRG_EN | M360_BRG_EXTC_BRGCLK | ((divisor - 1) << 1) | div16;
+}
+
+/*
+ * Hardware-dependent portion of tcsetattr().
+ */
+static int
+smc1SetAttributes (int minor, const struct termios *t)
+{
+ int baud;
+
+ baud = rtems_termios_baud_to_number(t->c_ospeed);
+ if (baud > 0)
+ m360.brgc1 = smc1BRGC (baud);
+ return 0;
+}
+
+/*
+ * Interrupt handler
+ */
+static rtems_isr
+smc1InterruptHandler (rtems_vector_number v)
+{
+ /*
+ * Buffer received?
+ */
+ if (m360.smc1.smce & 0x1) {
+ m360.smc1.smce = 0x1;
+ while ((smcRxBd->status & M360_BD_EMPTY) == 0) {
+ rtems_termios_enqueue_raw_characters (smc1ttyp,
+ (char *)smcRxBd->buffer,
+ smcRxBd->length);
+ smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP | M360_BD_INTERRUPT;
+ }
+ }
+
+ /*
+ * Buffer transmitted?
+ */
+ if (m360.smc1.smce & 0x2) {
+ m360.smc1.smce = 0x2;
+ if ((smcTxBd->status & M360_BD_READY) == 0)
+ rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
+ }
+ m360.cisr = 1UL << 4; /* Clear SMC1 interrupt-in-service bit */
+}
+
+static int
+smc1Initialize (int major, int minor, void *arg)
+{
+ /*
+ * Allocate buffer descriptors
+ */
+ smcRxBd = M360AllocateBufferDescriptors (1);
+ smcTxBd = M360AllocateBufferDescriptors (1);
+
+ /*
+ * Configure port B pins to enable SMTXD1 and SMRXD1 pins
+ */
+ m360.pbpar |= 0xC0;
+ m360.pbdir &= ~0xC0;
+ m360.pbodr &= ~0xC0;
+
+ /*
+ * Set up BRG1 (9,600 baud)
+ */
+ m360.brgc1 = M360_BRG_RST;
+ m360.brgc1 = smc1BRGC (console_baud_rate);
+
+ /*
+ * Put SMC1 in NMSI mode, connect SMC1 to BRG1
+ */
+ m360.simode |= M360_SI_SMC1_BRG1;
+
+ /*
+ * Set up SMC1 parameter RAM common to all protocols
+ */
+ m360.smc1p.rbase = (char *)smcRxBd - (char *)&m360;
+ m360.smc1p.tbase = (char *)smcTxBd - (char *)&m360;
+ m360.smc1p.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
+ m360.smc1p.tfcr = M360_TFCR_MOT | M360_TFCR_DMA_SPACE;
+ if (m360_smc1_interrupt)
+ m360.smc1p.mrblr = RXBUFSIZE;
+ else
+ m360.smc1p.mrblr = 1;
+
+ /*
+ * Set up SMC1 parameter RAM UART-specific parameters
+ */
+ m360.smc1p.un.uart.max_idl = 10;
+ m360.smc1p.un.uart.brklen = 0;
+ m360.smc1p.un.uart.brkec = 0;
+ m360.smc1p.un.uart.brkcr = 0;
+
+ /*
+ * Set up the Receive Buffer Descriptor
+ */
+ smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP | M360_BD_INTERRUPT;
+ smcRxBd->length = 0;
+ smcRxBd->buffer = rxBuf;
+
+ /*
+ * Setup the Transmit Buffer Descriptor
+ */
+ smcTxBd->status = M360_BD_WRAP;
+
+ /*
+ * Set up SMC1 general and protocol-specific mode registers
+ */
+ m360.smc1.smce = ~0; /* Clear any pending events */
+ m360.smc1.smcm = 0; /* Mask all interrupt/event sources */
+ m360.smc1.smcmr = M360_SMCMR_CLEN(9) | M360_SMCMR_SM_UART;
+
+ /*
+ * Send "Init parameters" command
+ */
+ M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SMC1);
+
+ /*
+ * Enable receiver and transmitter
+ */
+ m360.smc1.smcmr |= M360_SMCMR_TEN | M360_SMCMR_REN;
+
+ if (m360_smc1_interrupt) {
+ rtems_isr_entry old_handler;
+
+ (void) rtems_interrupt_catch (smc1InterruptHandler,
+ (m360.cicr & 0xE0) | 0x04,
+ &old_handler);
+ m360.smc1.smcm = 3; /* Enable SMC1 TX and RX interrupts */
+ m360.cimr |= 1UL << 4; /* Enable SMC1 interrupts */
+ }
+
+ return 0;
+}
+
+static int
+smc1PollRead (int minor)
+{
+ unsigned char c;
+
+ if (smcRxBd->status & M360_BD_EMPTY)
+ return -1;
+ c = rxBuf[0];
+ smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP;
+ return c;
+}
+
+/*
+ * Device-dependent write routine
+ * Interrupt-driven devices:
+ * Begin transmission of as many characters as possible (minimum is 1).
+ * Polling devices:
+ * Transmit all characters.
+ */
+static ssize_t
+smc1InterruptWrite (int minor, const char *buf, size_t len)
+{
+ if (len > 0) {
+ smcTxBd->buffer = (char *)buf;
+ smcTxBd->length = len;
+ smcTxBd->status = M360_BD_READY | M360_BD_WRAP | M360_BD_INTERRUPT;
+ }
+
+ return 0;
+}
+
+static ssize_t
+smc1PollWrite (int minor, const char *buf, size_t len)
+{
+ size_t retval = len;
+ while (len--) {
+ static char txBuf;
+ while (smcTxBd->status & M360_BD_READY)
+ continue;
+ txBuf = *buf++;
+ smcTxBd->buffer = &txBuf;
+ smcTxBd->length = 1;
+ smcTxBd->status = M360_BD_READY | M360_BD_WRAP;
+ }
+ return retval;
+}
+
+/*
+ ***************
+ * BOILERPLATE *
+ ***************
+ */
+
+/*
+ * Reserve resources consumed by this driver
+ *
+ * NOTE: This is in another file to reduce dependencies on the minimum size.
+ */
+
+/*
+ * Initialize and register the device
+ */
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_status_code status;
+
+ /*
+ * Set up TERMIOS
+ */
+ rtems_termios_initialize ();
+
+ /*
+ * Register the device
+ */
+ status = rtems_io_register_name ("/dev/console", major, 0);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Open the device
+ */
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_status_code sc;
+ static const rtems_termios_callbacks intrCallbacks = {
+ smc1Initialize, /* firstOpen */
+ NULL, /* lastClose */
+ NULL, /* pollRead */
+ smc1InterruptWrite, /* write */
+ smc1SetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 1 /* outputUsesInterrupts */
+ };
+ static const rtems_termios_callbacks pollCallbacks = {
+ smc1Initialize, /* firstOpen */
+ NULL, /* lastClose */
+ smc1PollRead, /* pollRead */
+ smc1PollWrite, /* write */
+ smc1SetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 0 /* outputUsesInterrupts */
+ };
+
+ /*
+ * Do generic termios initialization
+ */
+ if (m360_smc1_interrupt) {
+ rtems_libio_open_close_args_t *args = arg;
+
+ sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
+ smc1ttyp = args->iop->data1;
+ }
+ else {
+ sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
+ }
+ return sc;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * Read from the device
+ */
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_read (arg);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * Handle ioctl request.
+ */
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_ioctl (arg);
+}