diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 1999-02-17 20:24:53 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 1999-02-17 20:24:53 +0000 |
commit | ee733965291f61dd959c0f75659b0482df7a64ca (patch) | |
tree | 1b7cd7bafa0e265b562fb8c6df14070293161c9a /c/src/lib/libcpu/powerpc/mpc860/console-generic/console-generic.c | |
parent | Patch from Eric Valette <valette@crf.canon.fr> to undo the patch (diff) | |
download | rtems-ee733965291f61dd959c0f75659b0482df7a64ca.tar.bz2 |
Jay Monkman <jmonkman@frasca.com> submitted the eth_comm BSP for a PPC860
based board.
Diffstat (limited to '')
-rw-r--r-- | c/src/lib/libcpu/powerpc/mpc860/console-generic/console-generic.c | 938 |
1 files changed, 938 insertions, 0 deletions
diff --git a/c/src/lib/libcpu/powerpc/mpc860/console-generic/console-generic.c b/c/src/lib/libcpu/powerpc/mpc860/console-generic/console-generic.c new file mode 100644 index 0000000000..bbf9748c12 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc860/console-generic/console-generic.c @@ -0,0 +1,938 @@ +/* + * 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 + * SCC3 4 + * SCC4 5 + * 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 <mpc860.h> +#include <mpc860/console.h> +#include <stdlib.h> +#include <unistd.h> +#include <termios.h> + +#define NIFACES 6 /* 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 m860BufferDescriptor_t *RxBd[NIFACES], *TxBd[NIFACES]; + +/* + * Device-specific routines + */ +static int m860_get_brg_cd(int); +unsigned char m860_get_brg_clk(int); +void m860_console_reserve_resources(rtems_configuration_table *); +unsigned char m860_get_brg_clk(int); + + +/* + * Compute baud-rate-generator configuration register value + */ +static int +m860_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 M860_BRG_EN | M860_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 m860_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: + m860.brgc1 = M860_BRG_RST; + m860.brgc1 = m860_get_brg_cd(baud); + break; + case 1: + m860.brgc2 = M860_BRG_RST; + m860.brgc2 = m860_get_brg_cd(baud); + break; + case 2: + m860.brgc3 = M860_BRG_RST; + m860.brgc3 = m860_get_brg_cd(baud); + break; + case 3: + m860.brgc4 = M860_BRG_RST; + m860.brgc4 = m860_get_brg_cd(baud); + break; + } + return i; + } + + else + return 0xff; +} + +/* + * Hardware-dependent portion of tcsetattr(). + */ +int +m860_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 = m860_get_brg_clk(baud); /* 4 BRGs, 6 serial ports - hopefully */ + /* at least 2 ports will be the same */ + m860.simode |= brg << (12 + ((minor) * 16)); + } + return 0; +} + +int +m860_scc_set_attributes (int minor, const struct termios *t) +{ + /* + * minor must be 2, 3, 4 or 5 + */ + 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 = m860_get_brg_clk(baud); /* 4 BRGs, 5 serial ports - hopefully */ + /* at least 2 ports will be the same */ + m860.sicr |= (brg << (3 + ((minor-2) * 8))) | + (brg << ((minor-2) * 8)); + } + return 0; +} + +void +m860_scc_initialize (int port) /* port is the SCC # (i.e. 1, 2, 3 or 4) */ +{ + unsigned char brg; + volatile m860SCCparms_t *sccparms; + volatile m860SCCRegisters_t *sccregs; + + /* + * Allocate buffer descriptors + */ + RxBd[port+1] = M860AllocateBufferDescriptors(1); + TxBd[port+1] = M860AllocateBufferDescriptors(1); + + /* + * Configure ports A and B to enable TXDx and RXDx pins + */ + m860.papar |= (0xC << ((port-2) * 2)); + m860.padir &= ~(0xC << ((port-2) * 2)); + m860.pbdir |= (0x04 << (port-2)); + m860.paodr &= ~(0x8 << ((port-2) * 2)); + m860.pbdat &= ~(0x04 << (port-2)); + + /* SCC2 is the only one with handshaking lines */ + /* + if (port == 2) { + m860.pcpar |= (0x02); + m860.pcpar &= ~(0xc0); + m860.pcdir &= ~(0xc2); + m860.pcso |= (0xc0); + } + */ + + brg = m860_get_brg_clk(9600); /* 4 BRGs, 5 serial ports - hopefully */ + /* at least 2 ports will be the same */ + + /* + * Set up SDMA + */ + m860.sdcr = 0x01; /* as recommended p 16-80, sec 16.10.2.1 MPC860UM/AD */ + + + m860.sicr &= ~(0xff << ((port-1) * 8)); + m860.sicr |= (brg << (3 + ((port-1) * 8))) | (brg << ((port-1) * 8)); + + /* + * Set up SMC1 parameter RAM common to all protocols + */ + if (port == 1) { + sccparms = (m860SCCparms_t*)&m860.scc1p; + sccregs = &m860.scc1; + } + else if (port == 2) { + sccparms = &m860.scc2p; + sccregs = &m860.scc2; + } + else if (port == 3) { + sccparms = &m860.scc3p; + sccregs = &m860.scc3; + } + else { + sccparms = &m860.scc4p; + sccregs = &m860.scc4; + } + + sccparms->rbase = (char *)RxBd[port+1] - (char *)&m860; + sccparms->tbase = (char *)TxBd[port+1] - (char *)&m860; + + if (port == 1) + M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SCC1); + else if (port == 2) + M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SCC2); + else if (port == 3) + M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SCC3); + else if (port == 4) + M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SCC4); + + sccparms->rfcr = M860_RFCR_MOT | M860_RFCR_DMA_SPACE(0); + sccparms->tfcr = M860_TFCR_MOT | M860_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 = M860_BD_EMPTY | M860_BD_WRAP | + M860_BD_INTERRUPT; + RxBd[port+1]->length = 0; + RxBd[port+1]->buffer = malloc(RXBUFSIZE); + + /* + * Setup the Transmit Buffer Descriptor + */ + TxBd[port+1]->status = M860_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 +m860_smc_initialize (int port) /* port is the SMC number (i.e. 1 or 2) */ +{ + unsigned char brg; + + /* + * Allocate buffer descriptors + */ + RxBd[port-1] = M860AllocateBufferDescriptors (1); + TxBd[port-1] = M860AllocateBufferDescriptors (1); + + /* + * Configure port B pins to enable SMTXDx and SMRXDx pins + */ + m860.pbpar |= (0xC0 << ((port-1) * 4)); + m860.pbdir &= ~(0xC0 << ((port-1) * 4)); + m860.pbdir |= (0x01 << (port-1)); + m860.pbodr &= ~(0xC0 << ((port-1) * 4)); + m860.pbdat &= ~(0x01 << (port-1)); + + /* + * Set up BRG1 (9,600 baud) + */ + brg = m860_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 + */ + m860.simode &= ~0x7000 << ((port-1) * 8); + m860.simode |= brg << (12 + ((port-1) * 8)); + + /* + * Set up SMC1 parameter RAM common to all protocols + */ + if (port == 1) { + m860.smc1p.rbase = (char *)RxBd[port-1] - (char *)&m860; + m860.smc1p.tbase = (char *)TxBd[port-1] - (char *)&m860; + m860.smc1p.rfcr = M860_RFCR_MOT | M860_RFCR_DMA_SPACE(0); + m860.smc1p.tfcr = M860_TFCR_MOT | M860_TFCR_DMA_SPACE(0); + m860.smc1p.mrblr = RXBUFSIZE; + + /* + * Set up SMC1 parameter RAM UART-specific parameters + */ + m860.smc1p.un.uart.max_idl = 10; + m860.smc1p.un.uart.brklen = 0; + m860.smc1p.un.uart.brkec = 0; + m860.smc1p.un.uart.brkcr = 0; + + } + else { + m860.smc2p.rbase = (char *)RxBd[port-1] - (char *)&m860; + m860.smc2p.tbase = (char *)TxBd[port-1] - (char *)&m860; + m860.smc2p.rfcr = M860_RFCR_MOT | M860_RFCR_DMA_SPACE(0); + m860.smc2p.tfcr = M860_TFCR_MOT | M860_TFCR_DMA_SPACE(0); + m860.smc2p.mrblr = RXBUFSIZE; + + /* + * Set up SMC2 parameter RAM UART-specific parameters + */ + m860.smc2p.un.uart.max_idl = 10; + m860.smc2p.un.uart.brklen = 0; + m860.smc2p.un.uart.brkec = 0; + m860.smc2p.un.uart.brkcr = 0; + } + + /* + * Set up the Receive Buffer Descriptor + */ + RxBd[port-1]->status = M860_BD_EMPTY | M860_BD_WRAP | + M860_BD_INTERRUPT; + RxBd[port-1]->length = 0; + RxBd[port+3]->buffer = malloc(RXBUFSIZE); + + /* + * Setup the Transmit Buffer Descriptor + */ + TxBd[port-1]->status = M860_BD_WRAP; + + /* + * Set up SMCx general and protocol-specific mode registers + */ + if (port == 1) { + m860.smc1.smce = ~0; /* Clear any pending events */ + m860.smc1.smcm = 0; /* Mask all interrupt/event sources */ + m860.smc1.smcmr = M860_SMCMR_CLEN(9) | M860_SMCMR_SM_UART; + + /* + * Send "Init parameters" command + */ + M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SMC1); + + /* + * Enable receiver and transmitter + */ + m860.smc1.smcmr |= M860_SMCMR_TEN | M860_SMCMR_REN; + } + else { + m860.smc2.smce = ~0; /* Clear any pending events */ + m860.smc2.smcm = 0; /* Mask all interrupt/event sources */ + m860.smc2.smcmr = M860_SMCMR_CLEN(9) | M860_SMCMR_SM_UART; + + /* + * Send "Init parameters" command + */ + M860ExecuteRISC (M860_CR_OP_INIT_RX_TX | M860_CR_CHAN_SMC2); + + /* + * Enable receiver and transmitter + */ + m860.smc2.smcmr |= M860_SMCMR_TEN | M860_SMCMR_REN; + } +} + +int +m860_char_poll_read (int minor) +{ + unsigned char c; + rtems_unsigned32 level; + + _CPU_ISR_Disable(level); + if (RxBd[minor]->status & M860_BD_EMPTY) { + _CPU_ISR_Enable(level); + return -1; + } + c = ((char *)RxBd[minor]->buffer)[0]; + RxBd[minor]->status = M860_BD_EMPTY | M860_BD_WRAP; + _CPU_ISR_Enable(level); + return c; +} + +int +m860_char_poll_write (int minor, const char *buf, int len) +{ + while (len--) { + while (TxBd[minor]->status & M860_BD_READY) + continue; + txBuf[minor] = *buf++; + TxBd[minor]->buffer = &txBuf[minor]; + TxBd[minor]->length = 1; + TxBd[minor]->status = M860_BD_READY | M860_BD_WRAP; + } + return 0; +} + +/* + * Interrupt handler + */ +rtems_isr +m860_scc1_console_interrupt_handler (rtems_vector_number v) +{ + /* + * Buffer received? + */ + if ((m860.scc1.sccm & 0x1) && (m860.scc1.scce & 0x1)) { + m860.scc1.scce = 0x1; + /* m860.scc1.sccm &= ~0x1;*/ + + while ((RxBd[SCC1_MINOR]->status & M860_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 = M860_BD_EMPTY | M860_BD_WRAP | + M860_BD_INTERRUPT; + } + } + + /* + * Buffer transmitted? + */ +#if 0 + if (m860.smc1.smce & 0x2) { + m860.smc1.smce = 0x2; + if ((smcTxBd->status & M360_BD_READY) == 0) + rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length); + } +#endif + m860.cisr = 1UL << 30; /* Clear SCC1 interrupt-in-service bit */ +} + +rtems_isr +m860_scc2_console_interrupt_handler (rtems_vector_number v) +{ + /* + * Buffer received? + */ + if ((m860.scc2.sccm & 0x1) && (m860.scc2.scce & 0x1)) { + m860.scc2.scce = 0x1; + /* m860.scc2.sccm &= ~0x1;*/ + + while ((RxBd[SCC2_MINOR]->status & M860_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 = M860_BD_EMPTY | M860_BD_WRAP | + M860_BD_INTERRUPT; + } + } + + /* + * Buffer transmitted? + */ +#if 0 + if (m860.smc1.smce & 0x2) { + m860.smc1.smce = 0x2; + if ((smcTxBd->status & M360_BD_READY) == 0) + rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length); + } +#endif + m860.cisr = 1UL << 29; /* Clear SCC2 interrupt-in-service bit */ +} + +rtems_isr +m860_scc3_console_interrupt_handler (rtems_vector_number v) +{ + /* + * Buffer received? + */ + if ((m860.scc3.sccm & 0x1) && (m860.scc3.scce & 0x1)) { + m860.scc3.scce = 0x1; + /* m860.scc3.sccm &= ~0x1;*/ + + while ((RxBd[SCC3_MINOR]->status & M860_BD_EMPTY) == 0) { + rxBufListTail[SCC3_MINOR]->next = malloc(sizeof(Buf_t)); + if (rxBufListTail[SCC3_MINOR]->next) { + rxBufListTail[SCC3_MINOR] = rxBufListTail[SCC3_MINOR]->next; + rxBufListTail[SCC3_MINOR]->buf = RxBd[SCC3_MINOR]->buffer; + rxBufListTail[SCC3_MINOR]->len = RxBd[SCC3_MINOR]->length; + rxBufListTail[SCC3_MINOR]->pos = 0; + rxBufListTail[SCC3_MINOR]->next = 0; + + RxBd[SCC3_MINOR]->buffer = malloc(RXBUFSIZE); + } + RxBd[SCC3_MINOR]->status = M860_BD_EMPTY | M860_BD_WRAP | + M860_BD_INTERRUPT; + } + } + + /* + * Buffer transmitted? + */ +#if 0 + if (m860.smc1.smce & 0x2) { + m860.smc1.smce = 0x2; + if ((smcTxBd->status & M360_BD_READY) == 0) + rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length); + } +#endif + m860.cisr = 1UL << 28; /* Clear SCC3 interrupt-in-service bit */ +} + +rtems_isr +m860_scc4_console_interrupt_handler (rtems_vector_number v) +{ + /* + * Buffer received? + */ + if ((m860.scc4.sccm & 0x1) && (m860.scc4.scce & 0x1)) { + m860.scc4.scce = 0x1; + /* m860.scc4.sccm &= ~0x1;*/ + + while ((RxBd[SCC4_MINOR]->status & M860_BD_EMPTY) == 0) { + rxBufListTail[SCC4_MINOR]->next = malloc(sizeof(Buf_t)); + if (rxBufListTail[SCC4_MINOR]->next) { + rxBufListTail[SCC4_MINOR] = rxBufListTail[SCC4_MINOR]->next; + rxBufListTail[SCC4_MINOR]->buf = RxBd[SCC4_MINOR]->buffer; + rxBufListTail[SCC4_MINOR]->len = RxBd[SCC4_MINOR]->length; + rxBufListTail[SCC4_MINOR]->pos = 0; + rxBufListTail[SCC4_MINOR]->next = 0; + + RxBd[SCC4_MINOR]->buffer = malloc(RXBUFSIZE); + } + RxBd[SCC4_MINOR]->status = M860_BD_EMPTY | M860_BD_WRAP | + M860_BD_INTERRUPT; + } + } + + /* + * Buffer transmitted? + */ +#if 0 + if (m860.smc1.smce & 0x2) { + m860.smc1.smce = 0x2; + if ((smcTxBd->status & M360_BD_READY) == 0) + rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length); + } +#endif + m860.cisr = 1UL << 27; /* Clear SCC4 interrupt-in-service bit */ +} + +rtems_isr +m860_smc1_console_interrupt_handler (rtems_vector_number v) +{ + /* + * Buffer received? + */ + if (m860.smc1.smce & 0x1) { + m860.smc1.smce = 0x1; + /* m860.scc2.sccm &= ~0x1;*/ + + while ((RxBd[SMC1_MINOR]->status & M860_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 = M860_BD_EMPTY | M860_BD_WRAP | + M860_BD_INTERRUPT; + } + } + + /* + * Buffer transmitted? + */ +#if 0 + if (m860.smc1.smce & 0x2) { + m860.smc1.smce = 0x2; + if ((smcTxBd->status & M360_BD_READY) == 0) + rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length); + } +#endif + m860.cisr = 1UL << 4; /* Clear SMC1 interrupt-in-service bit */ +} + +rtems_isr +m860_smc2_console_interrupt_handler (rtems_vector_number v) +{ + /* + * Buffer received? + */ + if (m860.smc2.smce & 0x1) { + m860.smc2.smce = 0x1; + + while ((RxBd[SMC2_MINOR]->status & M860_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 = M860_BD_EMPTY | M860_BD_WRAP | + M860_BD_INTERRUPT; + } + } + + /* + * Buffer transmitted? + */ +#if 0 + if (m860.smc1.smce & 0x2) { + m860.smc1.smce = 0x2; + if ((smcTxBd->status & M360_BD_READY) == 0) + rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length); + } +#endif + m860.cisr = 1UL << 3; /* Clear SMC2 interrupt-in-service bit */ +} + + +int +m860_buf_poll_read (int minor, char **buf) +{ + int len; + + if (RxBd[minor]->status & M860_BD_EMPTY) + return -1; + + RxBd[minor]->buffer = malloc(RXBUFSIZE); /* I hope this succeeds ... */ + len = RxBd[minor]->length; + RxBd[minor]->status = M860_BD_EMPTY | M860_BD_WRAP; + + return len; +} + +int +m860_buf_poll_write (int minor, char *buf, int len) +{ + static char *last_buf[6]; + + while (TxBd[minor]->status & M860_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 = M860_BD_READY | M860_BD_WRAP; + return 0; +} + +/* + * This is needed in case we use TERMIOS + */ +void m860_console_reserve_resources(rtems_configuration_table *configuration) +{ + rtems_termios_reserve_resources (configuration, 1); +} + +void m860_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 m860_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 + */ + m860.cicr = 0x00e43e80; /* SCaP=SCC1, SCbP=SCC2, SCcP=SCC3, + SCdP=SCC4, IRL=1, HP=SCC1, IEN=1 */ + m860.simask |= M860_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 m860_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 + */ +/* m860.cicr = 0x00e43e80; /* SCaP=SCC1, SCbP=SCC2, SCcP=SCC3, + SCdP=SCC4, IRL=1, HP=SCC1, IEN=1 */ +/* m860.simask |= M860_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]; + } + m860_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) + * + */ |