summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/powerpc/mpc821/console-generic/console-generic.c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1999-04-07 15:57:05 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1999-04-07 15:57:05 +0000
commit3084de251365100266522ed0166a2aa2e3cdc714 (patch)
tree88c17ba84bdb223033fb5f441e417f8aef4e0837 /c/src/lib/libcpu/powerpc/mpc821/console-generic/console-generic.c
parentchanged version to 19990406 (diff)
downloadrtems-3084de251365100266522ed0166a2aa2e3cdc714.tar.bz2
MPC821 support and PPC patches from Andrew Bray <andy@madhouse.demon.co.uk>:
In c/src/exec/score/cpu/powerpc/rtems/score/ppc.h: A lot of hardware interrupts were omitted. Patch enclosed. I have also added the 821. In c/src/exec/score/cpu/powerpc/rtems/score/cpu.h: My patch adds the 821. In c/src/exec/score/cpu/powerpc/cpu.c: I have added the MPC821, and also fixed up for the missing hardware interrupts. It is also inconsistent with c/src/lib/libcpu/powerpc/mpc860/vectors/vectors.S. This has been fixed. In c/src/lib/libcpu/powerpc/mpc860/vectors/vectors.S: Fixed an inconsistency with cpu.c. I also include some new files to go with the above patches. These are the cpu library rtems-19990331/c/src/lib/libcpu/powerpc/mpc821/* and c/src/exec/score/cpu/powerpc/mpc821.h which are minor modifications of the 860 equivalents. Other comments: The various accesses to the DPRAM on the 860 are done with a linktime symbol. This could be done dynamically at run time by reading the immr register, and masking off the lower 16 bits. This takes the same amount of time as loading an address constant, and the same number of instructions as well (2). In c/src/lib/libcpu/powerpc/mpc860/console-generic/console-generic.c: This will silently fail if you attempt to use SCC1. This is only relevant if you are not using SCC1 for ethernet. This file also sets one of port B output pins for each port. This is NOT generic, it should be in the BSP specific console driver.
Diffstat (limited to 'c/src/lib/libcpu/powerpc/mpc821/console-generic/console-generic.c')
-rw-r--r--c/src/lib/libcpu/powerpc/mpc821/console-generic/console-generic.c846
1 files changed, 846 insertions, 0 deletions
diff --git a/c/src/lib/libcpu/powerpc/mpc821/console-generic/console-generic.c b/c/src/lib/libcpu/powerpc/mpc821/console-generic/console-generic.c
new file mode 100644
index 0000000000..dec222fb3f
--- /dev/null
+++ b/c/src/lib/libcpu/powerpc/mpc821/console-generic/console-generic.c
@@ -0,0 +1,846 @@
+/*
+ * General Serial I/O functions.
+ *
+ * This file contains the functions for performing serial I/O.
+ * The actual system calls (console_*) should be in the BSP part
+ * of the source tree. That way different BSPs can use whichever
+ * SMCs and SCCs they want. Originally, all the stuff was in
+ * this file, and it caused problems with one BSP using SCC2
+ * as /dev/console, others using SMC1 for /dev/console, etc.
+ *
+ * On-chip resources used:
+ * resource minor note
+ * SMC1 0
+ * SMC2 1
+ * SCC1 2 (shared with ethernet driver)
+ * SCC2 3
+ * BRG1
+ * BRG2
+ * BRG3
+ * BRG4
+ * Author: Jay Monkman (jmonkman@frasca.com)
+ * Copyright (C) 1998 by Frasca International, Inc.
+ *
+ * Derived from c/src/lib/libbsp/m68k/gen360/console/console.c:
+ *
+ * Author:
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ *
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <mpc821.h>
+#include <mpc821/console.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+
+#define NIFACES 4 /* number of console devices (serial ports) */
+
+extern rtems_cpu_table Cpu_table; /* owned by BSP */
+
+static Buf_t *rxBufList[NIFACES];
+static Buf_t *rxBufListTail[NIFACES];
+
+/*
+ * Interrupt-driven input buffer
+ */
+#define RXBUFSIZE 16
+
+
+/*
+ * I/O buffers and pointers to buffer descriptors
+ */
+static volatile char txBuf[NIFACES];
+
+static volatile m821BufferDescriptor_t *RxBd[NIFACES], *TxBd[NIFACES];
+
+/*
+ * Device-specific routines
+ */
+static int m821_get_brg_cd(int);
+unsigned char m821_get_brg_clk(int);
+void m821_console_reserve_resources(rtems_configuration_table *);
+unsigned char m821_get_brg_clk(int);
+
+
+/*
+ * Compute baud-rate-generator configuration register value
+ */
+static int
+m821_get_brg_cd (int baud)
+{
+ int divisor;
+ int div16 = 0;
+
+ divisor = ((Cpu_table.clock_speed / 16) + (baud / 2)) / baud;
+ if (divisor > 4096) {
+ div16 = 1;
+ divisor = (divisor + 8) / 16;
+ }
+ return M821_BRG_EN | M821_BRG_EXTC_BRGCLK |
+ ((divisor - 1) << 1) | div16;
+}
+
+
+/* this function will fail if more that 4 baud rates have been selected */
+/* at any time since the OS started. It needs to be fixed. FIXME */
+unsigned char m821_get_brg_clk(int baud)
+{
+ static short brg_spd[4];
+ static char brg_used[4];
+ int i;
+
+ /* first try to find a BRG that is already at the right speed */
+ for (i=0; i<4; i++) {
+ if (brg_spd[i] == baud) {
+ break;
+ }
+ }
+
+ if (i==4) { /* I guess we didn't find one */
+ for (i=0; i<4; i++) {
+ if (brg_used[i] == 0) {
+ break;
+ }
+ }
+ }
+ if (i != 4) {
+ brg_used[i]++;
+ brg_spd[i]=baud;
+ switch (i) {
+ case 0:
+ m821.brgc1 = M821_BRG_RST;
+ m821.brgc1 = m821_get_brg_cd(baud);
+ break;
+ case 1:
+ m821.brgc2 = M821_BRG_RST;
+ m821.brgc2 = m821_get_brg_cd(baud);
+ break;
+ case 2:
+ m821.brgc3 = M821_BRG_RST;
+ m821.brgc3 = m821_get_brg_cd(baud);
+ break;
+ case 3:
+ m821.brgc4 = M821_BRG_RST;
+ m821.brgc4 = m821_get_brg_cd(baud);
+ break;
+ }
+ return i;
+ }
+
+ else
+ return 0xff;
+}
+
+/*
+ * Hardware-dependent portion of tcsetattr().
+ */
+int
+m821_smc_set_attributes (int minor, const struct termios *t)
+{
+ /*
+ * minor must be 0 or 1
+ */
+ int baud;
+ int brg;
+ switch (t->c_cflag & CBAUD) {
+ default: baud = -1; break;
+ case B50: baud = 50; break;
+ case B75: baud = 75; break;
+ case B110: baud = 110; break;
+ case B134: baud = 134; break;
+ case B150: baud = 150; break;
+ case B200: baud = 200; break;
+ case B300: baud = 300; break;
+ case B600: baud = 600; break;
+ case B1200: baud = 1200; break;
+ case B1800: baud = 1800; break;
+ case B2400: baud = 2400; break;
+ case B4800: baud = 4800; break;
+ case B9600: baud = 9600; break;
+ case B19200: baud = 19200; break;
+ case B38400: baud = 38400; break;
+ case B57600: baud = 57600; break;
+ case B115200: baud = 115200; break;
+ case B230400: baud = 230400; break;
+ case B460800: baud = 460800; break;
+ }
+ if (baud > 0) {
+ brg = m821_get_brg_clk(baud); /* 4 BRGs, 4 serial ports - hopefully */
+ /* at least 2 ports will be the same */
+ m821.simode |= brg << (12 + ((minor) * 16));
+ }
+ return 0;
+}
+
+int
+m821_scc_set_attributes (int minor, const struct termios *t)
+{
+ /*
+ * minor must be 2, or 3
+ */
+ int baud;
+ int brg;
+ switch (t->c_cflag & CBAUD) {
+ default: baud = -1; break;
+ case B50: baud = 50; break;
+ case B75: baud = 75; break;
+ case B110: baud = 110; break;
+ case B134: baud = 134; break;
+ case B150: baud = 150; break;
+ case B200: baud = 200; break;
+ case B300: baud = 300; break;
+ case B600: baud = 600; break;
+ case B1200: baud = 1200; break;
+ case B1800: baud = 1800; break;
+ case B2400: baud = 2400; break;
+ case B4800: baud = 4800; break;
+ case B9600: baud = 9600; break;
+ case B19200: baud = 19200; break;
+ case B38400: baud = 38400; break;
+ case B57600: baud = 57600; break;
+ case B115200: baud = 115200; break;
+ case B230400: baud = 230400; break;
+ case B460800: baud = 460800; break;
+ }
+ if (baud > 0) {
+ brg = m821_get_brg_clk(baud); /* 4 BRGs, 5 serial ports - hopefully */
+ /* at least 2 ports will be the same */
+ m821.sicr |= (brg << (3 + ((minor-2) * 8))) |
+ (brg << ((minor-2) * 8));
+ }
+ return 0;
+}
+
+void
+m821_scc_initialize (int port) /* port is the SCC # (i.e. 1, 2, 3 or 4) */
+{
+ unsigned char brg;
+ volatile m821SCCparms_t *sccparms;
+ volatile m821SCCRegisters_t *sccregs;
+
+ /*
+ * Allocate buffer descriptors
+ */
+ RxBd[port+1] = M821AllocateBufferDescriptors(1);
+ TxBd[port+1] = M821AllocateBufferDescriptors(1);
+
+ /*
+ * Configure ports A and B to enable TXDx and RXDx pins
+ */
+ m821.papar |= (0xC << ((port-2) * 2));
+ m821.padir &= ~(0xC << ((port-2) * 2));
+ m821.pbdir |= (0x04 << (port-2));
+ m821.paodr &= ~(0x8 << ((port-2) * 2));
+ m821.pbdat &= ~(0x04 << (port-2));
+
+ /* SCC2 is the only one with handshaking lines */
+ /*
+ if (port == 2) {
+ m821.pcpar |= (0x02);
+ m821.pcpar &= ~(0xc0);
+ m821.pcdir &= ~(0xc2);
+ m821.pcso |= (0xc0);
+ }
+ */
+
+ brg = m821_get_brg_clk(9600); /* 4 BRGs, 5 serial ports - hopefully */
+ /* at least 2 ports will be the same */
+
+ /*
+ * Set up SDMA
+ */
+ m821.sdcr = 0x01; /* as recommended p 16-80, sec 16.10.2.1 MPC821UM/AD */
+
+
+ m821.sicr &= ~(0xff << ((port-1) * 8));
+ m821.sicr |= (brg << (3 + ((port-1) * 8))) | (brg << ((port-1) * 8));
+
+ /*
+ * Set up SCC1 parameter RAM common to all protocols
+ */
+ if (port == 1) {
+ sccparms = (m821SCCparms_t*)&m821.scc1p;
+ sccregs = &m821.scc1;
+ }
+ else if (port == 2) {
+ sccparms = &m821.scc2p;
+ sccregs = &m821.scc2;
+ }
+
+ sccparms->rbase = (char *)RxBd[port+1] - (char *)&m821;
+ sccparms->tbase = (char *)TxBd[port+1] - (char *)&m821;
+
+ if (port == 1)
+ M821ExecuteRISC (M821_CR_OP_INIT_RX_TX | M821_CR_CHAN_SCC1);
+ else if (port == 2)
+ M821ExecuteRISC (M821_CR_OP_INIT_RX_TX | M821_CR_CHAN_SCC2);
+
+ sccparms->rfcr = M821_RFCR_MOT | M821_RFCR_DMA_SPACE(0);
+ sccparms->tfcr = M821_TFCR_MOT | M821_TFCR_DMA_SPACE(0);
+ sccparms->mrblr = RXBUFSIZE;
+
+ sccparms->un.uart.max_idl = 10;
+ sccparms->un.uart.brklen = 0;
+ sccparms->un.uart.brkec = 0;
+ sccparms->un.uart.brkcr = 1;
+
+ sccparms->un.uart.parec = 0;
+ sccparms->un.uart.frmec = 0;
+ sccparms->un.uart.nosec = 0;
+
+ sccparms->un.uart.uaddr[0] = 0;
+ sccparms->un.uart.uaddr[1] = 0;
+ sccparms->un.uart.toseq = 0;
+
+ sccparms->un.uart.character[0] = 0x8000;
+ sccparms->un.uart.character[1] = 0x8000;
+ sccparms->un.uart.character[2] = 0x8000;
+ sccparms->un.uart.character[3] = 0x8000;
+ sccparms->un.uart.character[4] = 0x8000;
+ sccparms->un.uart.character[5] = 0x8000;
+ sccparms->un.uart.character[6] = 0x8000;
+ sccparms->un.uart.character[7] = 0x8000;
+
+ sccparms->un.uart.rccm = 0xc0ff;
+
+ /*
+ * Set up the Receive Buffer Descriptor
+ */
+ RxBd[port+1]->status = M821_BD_EMPTY | M821_BD_WRAP |
+ M821_BD_INTERRUPT;
+ RxBd[port+1]->length = 0;
+ RxBd[port+1]->buffer = malloc(RXBUFSIZE);
+
+ /*
+ * Setup the Transmit Buffer Descriptor
+ */
+ TxBd[port+1]->status = M821_BD_WRAP;
+
+ /*
+ * Set up SCCx general and protocol-specific mode registers
+ */
+ sccregs->scce = 0xffff;
+ sccregs->sccm = 0x0000;
+ sccregs->gsmr_h = 0x00000020;
+ sccregs->gsmr_l = 0x00028004;
+ sccregs->psmr = 0x3000;
+ sccregs->gsmr_l = 0x00028034;
+}
+
+void
+m821_smc_initialize (int port) /* port is the SMC number (i.e. 1 or 2) */
+{
+ unsigned char brg;
+
+ /*
+ * Allocate buffer descriptors
+ */
+ RxBd[port-1] = M821AllocateBufferDescriptors (1);
+ TxBd[port-1] = M821AllocateBufferDescriptors (1);
+
+ /*
+ * Configure port B pins to enable SMTXDx and SMRXDx pins
+ */
+ m821.pbpar |= (0xC0 << ((port-1) * 4));
+ m821.pbdir &= ~(0xC0 << ((port-1) * 4));
+ m821.pbdir |= (0x01 << (port-1));
+ m821.pbodr &= ~(0xC0 << ((port-1) * 4));
+ m821.pbdat &= ~(0x01 << (port-1));
+
+ /*
+ * Set up BRG1 (9,600 baud)
+ */
+ brg = m821_get_brg_clk(9600); /* 4 BRGs, 5 serial ports - hopefully */
+ /* at least 2 ports will be the same */
+
+ /*
+ * Put SMC in NMSI mode, connect SMC to BRG
+ */
+ m821.simode &= ~0x7000 << ((port-1) * 8);
+ m821.simode |= brg << (12 + ((port-1) * 8));
+
+ /*
+ * Set up SMC1 parameter RAM common to all protocols
+ */
+ if (port == 1) {
+ m821.smc1p.rbase = (char *)RxBd[port-1] - (char *)&m821;
+ m821.smc1p.tbase = (char *)TxBd[port-1] - (char *)&m821;
+ m821.smc1p.rfcr = M821_RFCR_MOT | M821_RFCR_DMA_SPACE(0);
+ m821.smc1p.tfcr = M821_TFCR_MOT | M821_TFCR_DMA_SPACE(0);
+ m821.smc1p.mrblr = RXBUFSIZE;
+
+ /*
+ * Set up SMC1 parameter RAM UART-specific parameters
+ */
+ m821.smc1p.un.uart.max_idl = 10;
+ m821.smc1p.un.uart.brklen = 0;
+ m821.smc1p.un.uart.brkec = 0;
+ m821.smc1p.un.uart.brkcr = 0;
+
+ }
+ else {
+ m821.smc2p.rbase = (char *)RxBd[port-1] - (char *)&m821;
+ m821.smc2p.tbase = (char *)TxBd[port-1] - (char *)&m821;
+ m821.smc2p.rfcr = M821_RFCR_MOT | M821_RFCR_DMA_SPACE(0);
+ m821.smc2p.tfcr = M821_TFCR_MOT | M821_TFCR_DMA_SPACE(0);
+ m821.smc2p.mrblr = RXBUFSIZE;
+
+ /*
+ * Set up SMC2 parameter RAM UART-specific parameters
+ */
+ m821.smc2p.un.uart.max_idl = 10;
+ m821.smc2p.un.uart.brklen = 0;
+ m821.smc2p.un.uart.brkec = 0;
+ m821.smc2p.un.uart.brkcr = 0;
+ }
+
+ /*
+ * Set up the Receive Buffer Descriptor
+ */
+ RxBd[port-1]->status = M821_BD_EMPTY | M821_BD_WRAP |
+ M821_BD_INTERRUPT;
+ RxBd[port-1]->length = 0;
+ RxBd[port+3]->buffer = malloc(RXBUFSIZE);
+
+ /*
+ * Setup the Transmit Buffer Descriptor
+ */
+ TxBd[port-1]->status = M821_BD_WRAP;
+
+ /*
+ * Set up SMCx general and protocol-specific mode registers
+ */
+ if (port == 1) {
+ m821.smc1.smce = ~0; /* Clear any pending events */
+ m821.smc1.smcm = 0; /* Mask all interrupt/event sources */
+ m821.smc1.smcmr = M821_SMCMR_CLEN(9) | M821_SMCMR_SM_UART;
+
+ /*
+ * Send "Init parameters" command
+ */
+ M821ExecuteRISC (M821_CR_OP_INIT_RX_TX | M821_CR_CHAN_SMC1);
+
+ /*
+ * Enable receiver and transmitter
+ */
+ m821.smc1.smcmr |= M821_SMCMR_TEN | M821_SMCMR_REN;
+ }
+ else {
+ m821.smc2.smce = ~0; /* Clear any pending events */
+ m821.smc2.smcm = 0; /* Mask all interrupt/event sources */
+ m821.smc2.smcmr = M821_SMCMR_CLEN(9) | M821_SMCMR_SM_UART;
+
+ /*
+ * Send "Init parameters" command
+ */
+ M821ExecuteRISC (M821_CR_OP_INIT_RX_TX | M821_CR_CHAN_SMC2);
+
+ /*
+ * Enable receiver and transmitter
+ */
+ m821.smc2.smcmr |= M821_SMCMR_TEN | M821_SMCMR_REN;
+ }
+}
+
+int
+m821_char_poll_read (int minor)
+{
+ unsigned char c;
+ rtems_unsigned32 level;
+
+ _CPU_ISR_Disable(level);
+ if (RxBd[minor]->status & M821_BD_EMPTY) {
+ _CPU_ISR_Enable(level);
+ return -1;
+ }
+ c = ((char *)RxBd[minor]->buffer)[0];
+ RxBd[minor]->status = M821_BD_EMPTY | M821_BD_WRAP;
+ _CPU_ISR_Enable(level);
+ return c;
+}
+
+int
+m821_char_poll_write (int minor, const char *buf, int len)
+{
+ while (len--) {
+ while (TxBd[minor]->status & M821_BD_READY)
+ continue;
+ txBuf[minor] = *buf++;
+ TxBd[minor]->buffer = &txBuf[minor];
+ TxBd[minor]->length = 1;
+ TxBd[minor]->status = M821_BD_READY | M821_BD_WRAP;
+ }
+ return 0;
+}
+
+/*
+ * Interrupt handler
+ */
+rtems_isr
+m821_scc1_console_interrupt_handler (rtems_vector_number v)
+{
+ /*
+ * Buffer received?
+ */
+ if ((m821.scc1.sccm & 0x1) && (m821.scc1.scce & 0x1)) {
+ m821.scc1.scce = 0x1;
+ /* m821.scc1.sccm &= ~0x1;*/
+
+ while ((RxBd[SCC1_MINOR]->status & M821_BD_EMPTY) == 0) {
+ rxBufListTail[SCC1_MINOR]->next = malloc(sizeof(Buf_t));
+ if (rxBufListTail[SCC1_MINOR]->next) {
+ rxBufListTail[SCC1_MINOR] = rxBufListTail[SCC1_MINOR]->next;
+ rxBufListTail[SCC1_MINOR]->buf = RxBd[SCC1_MINOR]->buffer;
+ rxBufListTail[SCC1_MINOR]->len = RxBd[SCC1_MINOR]->length;
+ rxBufListTail[SCC1_MINOR]->pos = 0;
+ rxBufListTail[SCC1_MINOR]->next = 0;
+
+ RxBd[SCC1_MINOR]->buffer = malloc(RXBUFSIZE);
+ }
+ RxBd[SCC1_MINOR]->status = M821_BD_EMPTY | M821_BD_WRAP |
+ M821_BD_INTERRUPT;
+ }
+ }
+
+ /*
+ * Buffer transmitted?
+ */
+#if 0
+ if (m821.smc1.smce & 0x2) {
+ m821.smc1.smce = 0x2;
+ if ((smcTxBd->status & M360_BD_READY) == 0)
+ rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
+ }
+#endif
+ m821.cisr = 1UL << 30; /* Clear SCC1 interrupt-in-service bit */
+}
+
+rtems_isr
+m821_scc2_console_interrupt_handler (rtems_vector_number v)
+{
+ /*
+ * Buffer received?
+ */
+ if ((m821.scc2.sccm & 0x1) && (m821.scc2.scce & 0x1)) {
+ m821.scc2.scce = 0x1;
+ /* m821.scc2.sccm &= ~0x1;*/
+
+ while ((RxBd[SCC2_MINOR]->status & M821_BD_EMPTY) == 0) {
+ rxBufListTail[SCC2_MINOR]->next = malloc(sizeof(Buf_t));
+ if (rxBufListTail[SCC2_MINOR]->next) {
+ rxBufListTail[SCC2_MINOR] = rxBufListTail[SCC2_MINOR]->next;
+ rxBufListTail[SCC2_MINOR]->buf = RxBd[SCC2_MINOR]->buffer;
+ rxBufListTail[SCC2_MINOR]->len = RxBd[SCC2_MINOR]->length;
+ rxBufListTail[SCC2_MINOR]->pos = 0;
+ rxBufListTail[SCC2_MINOR]->next = 0;
+
+ RxBd[SCC2_MINOR]->buffer = malloc(RXBUFSIZE);
+ }
+ RxBd[SCC2_MINOR]->status = M821_BD_EMPTY | M821_BD_WRAP |
+ M821_BD_INTERRUPT;
+ }
+ }
+
+ /*
+ * Buffer transmitted?
+ */
+#if 0
+ if (m821.smc1.smce & 0x2) {
+ m821.smc1.smce = 0x2;
+ if ((smcTxBd->status & M360_BD_READY) == 0)
+ rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
+ }
+#endif
+ m821.cisr = 1UL << 29; /* Clear SCC2 interrupt-in-service bit */
+}
+
+rtems_isr
+m821_smc1_console_interrupt_handler (rtems_vector_number v)
+{
+ /*
+ * Buffer received?
+ */
+ if (m821.smc1.smce & 0x1) {
+ m821.smc1.smce = 0x1;
+ /* m821.scc2.sccm &= ~0x1;*/
+
+ while ((RxBd[SMC1_MINOR]->status & M821_BD_EMPTY) == 0) {
+ rxBufListTail[SMC1_MINOR]->next = malloc(sizeof(Buf_t));
+ if (rxBufListTail[SMC1_MINOR]->next) {
+ rxBufListTail[SMC1_MINOR] = rxBufListTail[SMC1_MINOR]->next;
+ rxBufListTail[SMC1_MINOR]->buf = RxBd[SMC1_MINOR]->buffer;
+ rxBufListTail[SMC1_MINOR]->len = RxBd[SMC1_MINOR]->length;
+ rxBufListTail[SMC1_MINOR]->pos = 0;
+ rxBufListTail[SMC1_MINOR]->next = 0;
+
+ RxBd[SMC1_MINOR]->buffer = malloc(RXBUFSIZE);
+ }
+ RxBd[SMC1_MINOR]->status = M821_BD_EMPTY | M821_BD_WRAP |
+ M821_BD_INTERRUPT;
+ }
+ }
+
+ /*
+ * Buffer transmitted?
+ */
+#if 0
+ if (m821.smc1.smce & 0x2) {
+ m821.smc1.smce = 0x2;
+ if ((smcTxBd->status & M360_BD_READY) == 0)
+ rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
+ }
+#endif
+ m821.cisr = 1UL << 4; /* Clear SMC1 interrupt-in-service bit */
+}
+
+rtems_isr
+m821_smc2_console_interrupt_handler (rtems_vector_number v)
+{
+ /*
+ * Buffer received?
+ */
+ if (m821.smc2.smce & 0x1) {
+ m821.smc2.smce = 0x1;
+
+ while ((RxBd[SMC2_MINOR]->status & M821_BD_EMPTY) == 0) {
+ rxBufListTail[SMC2_MINOR]->next = malloc(sizeof(Buf_t));
+ if (rxBufListTail[SMC2_MINOR]->next) {
+ rxBufListTail[SMC2_MINOR] = rxBufListTail[SMC2_MINOR]->next;
+ rxBufListTail[SMC2_MINOR]->buf = RxBd[SMC2_MINOR]->buffer;
+ rxBufListTail[SMC2_MINOR]->len = RxBd[SMC2_MINOR]->length;
+ rxBufListTail[SMC2_MINOR]->pos = 0;
+ rxBufListTail[SMC2_MINOR]->next = 0;
+
+ RxBd[SMC2_MINOR]->buffer = malloc(RXBUFSIZE);
+ }
+ RxBd[SMC2_MINOR]->status = M821_BD_EMPTY | M821_BD_WRAP |
+ M821_BD_INTERRUPT;
+ }
+ }
+
+ /*
+ * Buffer transmitted?
+ */
+#if 0
+ if (m821.smc1.smce & 0x2) {
+ m821.smc1.smce = 0x2;
+ if ((smcTxBd->status & M360_BD_READY) == 0)
+ rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
+ }
+#endif
+ m821.cisr = 1UL << 3; /* Clear SMC2 interrupt-in-service bit */
+}
+
+
+int
+m821_buf_poll_read (int minor, char **buf)
+{
+ int len;
+
+ if (RxBd[minor]->status & M821_BD_EMPTY)
+ return -1;
+
+ RxBd[minor]->buffer = malloc(RXBUFSIZE); /* I hope this succeeds ... */
+ len = RxBd[minor]->length;
+ RxBd[minor]->status = M821_BD_EMPTY | M821_BD_WRAP;
+
+ return len;
+}
+
+int
+m821_buf_poll_write (int minor, char *buf, int len)
+{
+ static char *last_buf[6];
+
+ while (TxBd[minor]->status & M821_BD_READY)
+ continue;
+ if (last_buf[minor])
+ free(last_buf[minor]);
+ last_buf[minor] = buf;
+ TxBd[minor]->buffer = buf;
+ TxBd[minor]->length = len;
+ TxBd[minor]->status = M821_BD_READY | M821_BD_WRAP;
+ return 0;
+}
+
+/*
+ * This is needed in case we use TERMIOS
+ */
+void m821_console_reserve_resources(rtems_configuration_table *configuration)
+{
+ rtems_termios_reserve_resources (configuration, 1);
+}
+
+void m821_console_initialize(void)
+{
+ int i;
+
+ for (i=0; i < NIFACES; i++) {
+ rxBufList[i] = malloc(sizeof(Buf_t));
+ rxBufListTail[i] = rxBufList[i];
+ rxBufList[i]->buf = 0;
+ rxBufList[i]->len = 0;
+ rxBufList[i]->pos = 0;
+ rxBufList[i]->next = 0;
+ }
+}
+
+rtems_device_driver m821_console_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;
+ Buf_t *tmp_buf;
+ rtems_unsigned32 level;
+
+ /*
+ * Set up interrupts
+ * FIXME: DANGER: WARNING:
+ * CICR and SIMASK must be set in any module that uses
+ * the CPM. Currently those are console-generic.c and
+ * network.c. If the registers are not set the same
+ * in both places, strange things may happen.
+ * If they are only set in one place, then an application
+ * that used the other module won't work correctly.
+ * Put this comment in each module that sets these 2 registers
+ */
+ m821.cicr = 0x00e43e80; /* SCaP=SCC1, SCbP=SCC2, SCcP=SCC3,
+ SCdP=SCC4, IRL=1, HP=SCC1, IEN=1 */
+ m821.simask |= M821_SIMASK_LVM1;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+ buffer = rw_args->buffer;
+ maximum = rw_args->count;
+ count = 0;
+
+ while (count == 0) {
+ if (rxBufList[minor]->len) {
+ while ((count < maximum) &&
+ (rxBufList[minor]->pos < rxBufList[minor]->len)) {
+ buffer[count++] = rxBufList[minor]->buf[rxBufList[minor]->pos++];
+ }
+ _CPU_ISR_Disable(level);
+ if (rxBufList[minor]->pos == rxBufList[minor]->len) {
+ if (rxBufList[minor]->next) {
+ tmp_buf=rxBufList[minor]->next;
+ free (rxBufList[minor]->buf);
+ free (rxBufList[minor]);
+ rxBufList[minor]=tmp_buf;
+ }
+ else {
+ free(rxBufList[minor]->buf);
+ rxBufList[minor]->buf=0;
+ rxBufList[minor]->len=0;
+ rxBufList[minor]->pos=0;
+ }
+ }
+ _CPU_ISR_Enable(level);
+ }
+ else
+ if(rxBufList[minor]->next && !rxBufList[minor]->len) {
+ tmp_buf = rxBufList[minor];
+ rxBufList[minor] = rxBufList[minor]->next;
+ free(tmp_buf);
+ }
+ /* sleep(1);*/
+ }
+ rw_args->bytes_moved = count;
+ return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED;
+}
+
+rtems_device_driver m821_console_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 *in_buffer;
+ char *out_buffer;
+ int n;
+
+ /*
+ * Set up interrupts
+ * FIXME: DANGER: WARNING:
+ * CICR and SIMASK must be set in any module that uses
+ * the CPM. Currently those are console-generic.c and
+ * network.c. If the registers are not set the same
+ * in both places, strange things may happen.
+ * If they are only set in one place, then an application
+ * that used the other module won't work correctly.
+ * Put this comment in each module that sets these 2 registers
+ */
+/* m821.cicr = 0x00e43e80; /* SCaP=SCC1, SCbP=SCC2, SCcP=SCC3,
+ SCdP=SCC4, IRL=1, HP=SCC1, IEN=1 */
+/* m821.simask |= M821_SIMASK_LVM1; */
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ in_buffer = rw_args->buffer;
+ maximum = rw_args->count;
+
+ out_buffer = malloc(maximum*2); /* This is wasteful, but it won't */
+ /* be too small */
+
+ if (!out_buffer) {
+ rw_args->bytes_moved = 0;
+ return RTEMS_NO_MEMORY;
+ }
+ n=0;
+ for (count = 0; count < maximum; count++) {
+ if ( in_buffer[ count ] == '\n') {
+ out_buffer[count + n] = '\r';
+ n++;
+ }
+ out_buffer[count + n] = in_buffer[count];
+ }
+ m821_buf_poll_write(minor, out_buffer, maximum+n);
+ rw_args->bytes_moved = maximum;
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ * How to use the console.
+ * In your BSP, have the following functions:
+ *
+ * rtems_device_driver console_initialize(rtems_device_major_number major,
+ * rtems_device_minor_number minor,
+ * void *arg)
+ * rtems_device_driver console_open(rtems_device_major_number major,
+ * rtems_device_minor_number minor,
+ * void *arg)
+ * rtems_device_driver console_close(rtems_device_major_number major,
+ * rtems_device_minor_number minor,
+ * void *arg)
+ * rtems_device_driver console_read(rtems_device_major_number major,
+ * rtems_device_minor_number minor,
+ * void *arg)
+ * rtems_device_driver console_write(rtems_device_major_number major,
+ * rtems_device_minor_number minor,
+ * void *arg)
+ * rtems_device_driver console_control(rtems_device_major_number major,
+ * rtems_device_minor_number minor,
+ * void *arg)
+ *
+ */