📄 console.c
字号:
case B110: in_baud = 110; break; case B134: in_baud = 134; break; case B150: in_baud = 150; break; case B200: in_baud = 200; break; case B300: in_baud = 300; break; case B600: in_baud = 600; break; case B1200: in_baud = 1200; break; case B1800: in_baud = 1800; break; case B2400: in_baud = 2400; break; case B4800: in_baud = 4800; break; case B9600: in_baud = 9600; break; case B19200: in_baud = 19200; break; case B38400: in_baud = 38400; break; case B57600: in_baud = 57600; break; case B115200: in_baud = 115200; break; case B230400: in_baud = 230400; break; case B460800: in_baud = 460800; break; } /* Number of bits per char */ csize = 0x07; /* to avoid a warning */ switch ( t->c_cflag & CSIZE ) { case CS5: csize = 0x04; break; case CS6: csize = 0x05; break; case CS7: csize = 0x06; break; case CS8: csize = 0x07; break; } /* Parity */ if ( t->c_cflag & PARODD ) parodd = 0x80; /* Odd parity */ else parodd = 0; if ( t->c_cflag & PARENB ) parenb = 0x40; /* Parity enabled on Tx and Rx */ else parenb = 0x00; /* No parity on Tx and Rx */ /* CD2401 IGNPAR and INPCK bits are inverted wrt POSIX standard? */ if ( t->c_iflag & INPCK ) ignpar = 0; /* Check parity on input */ else ignpar = 0x10; /* Do not check parity on input */ if ( t->c_iflag & IGNPAR ) { inpck = 0x03; /* Discard error character */ parmrk = 0; } else { if ( t->c_iflag & PARMRK ) { inpck = 0x01; /* Translate to 0xFF 0x00 <char> */ parmrk = 0x04; } else { inpck = 0x01; /* Translate to 0x00 */ parmrk = 0; } } /* Stop bits */ if ( t->c_cflag & CSTOPB ) cstopb = 0x04; /* Two stop bits */ else cstopb = 0x02; /* One stop bit */ /* Modem flow control */ if ( t->c_cflag & CLOCAL ) hw_flow_ctl = 0x04; /* Always assert RTS before Tx */ else hw_flow_ctl = 0x07; /* Always assert RTS before Tx, wait for CTS and DSR */ /* XON/XOFF Tx flow control */ if ( t->c_iflag & IXON ) { sw_flow_ctl = 0x40; /* Tx in-band flow ctl enabled, wait for XON */ extra_flow_ctl = 0x30; /* Eat XON/XOFF, XON/XOFF in SCHR1, SCHR2 */ } else { sw_flow_ctl = 0; /* Tx in-band flow ctl disabled */ extra_flow_ctl = 0; /* Pass on XON/XOFF */ } /* CL/LF translation */ if ( t->c_iflag & ICRNL ) icrnl = 0x40; /* Map CR to NL on input */ else icrnl = 0; /* Pass on CR */ if ( t->c_iflag & INLCR ) inlcr = 0x20; /* Map NL to CR on input */ else inlcr = 0; /* Pass on NL */ if ( t->c_iflag & IGNCR ) igncr = 0x80; /* CR discarded on input */ else igncr = 0; /* Break handling */ if ( t->c_iflag & IGNBRK ) { ignbrk = 0x10; /* Ignore break on input */ brkint = 0x08; } else { if ( t->c_iflag & BRKINT ) { ignbrk = 0; /* Generate SIGINT (interrupt ) */ brkint = 0; } else { ignbrk = 0; /* Convert to 0x00 */ brkint = 0x08; } } /* Stripping */ if ( t->c_iflag & ISTRIP ) istrip = 0x80; /* Strip to 7 bits */ else istrip = 0; /* Leave as 8 bits */ rx_period = cd2401_bitrate_divisor( 20000000Ul, &in_baud ); tx_period = cd2401_bitrate_divisor( 20000000Ul, &out_baud ); /* * If this is the first time that the line characteristics are set up, then * the device must be re-initialized. * Also check if we need to change anything. It is preferable to not touch * the device if nothing changes. As soon as we touch it, it tends to * glitch. If anything changes, we reprogram all registers. This is * harmless. */ if ( ( CD2401_Channel_Info[minor].tty == 0 ) || ( cd2401->cor1 != (parodd | parenb | ignpar | csize) ) || ( cd2401->cor2 != (sw_flow_ctl | hw_flow_ctl) ) || ( cd2401->cor3 != (extra_flow_ctl | cstopb) ) || ( cd2401->cor6 != (igncr | icrnl | inlcr | ignbrk | brkint | parmrk | inpck) ) || ( cd2401->cor7 != istrip ) || ( cd2401->u1.async.schr1 != t->c_cc[VSTART] ) || ( cd2401->u1.async.schr2 != t->c_cc[VSTOP] ) || ( cd2401->rbpr != (unsigned char)rx_period ) || ( cd2401->rcor != (unsigned char)(rx_period >> 8) ) || ( cd2401->tbpr != (unsigned char)tx_period ) || ( cd2401->tcor != ( (tx_period >> 3) & 0xE0 ) ) ) need_reinitialization = TRUE; /* Write to the ports */ rtems_interrupt_disable (level); cd2401->car = minor; /* Select channel */ read_enabled = cd2401->csr & 0x80 ? TRUE : FALSE; if ( (t->c_cflag & CREAD ? TRUE : FALSE ) != read_enabled ) { /* Read enable status is changing */ need_reinitialization = TRUE; } if ( need_reinitialization ) { /* * Could not find a way to test whether the CD2401 was done transmitting. * The TxEmpty interrupt does not seem to indicate that the FIFO is empty * in DMA mode. So, just wait a while for output to drain. May not be * enough, but it will have to do (should be long enough for 1 char at * 9600 bsp)... */ cd2401_udelay( 2000L ); /* Clear channel */ cd2401_chan_cmd (minor, 0x40, 1); cd2401->car = minor; /* Select channel */ cd2401->cmr = 0x42; /* Interrupt Rx, DMA Tx, async mode */ cd2401->cor1 = parodd | parenb | ignpar | csize; cd2401->cor2 = sw_flow_ctl | hw_flow_ctl; cd2401->cor3 = extra_flow_ctl | cstopb; cd2401->cor4 = 0x0A; /* No DSR/DCD/CTS detect; FIFO threshold of 10 */ cd2401->cor5 = 0x0A; /* No DSR/DCD/CTS detect; DTR threshold of 10 */ cd2401->cor6 = igncr | icrnl | inlcr | ignbrk | brkint | parmrk | inpck; cd2401->cor7 = istrip; /* No LNext; ignore XON/XOFF if frame error; no tx translations */ /* Special char 1: XON character */ cd2401->u1.async.schr1 = t->c_cc[VSTART]; /* special char 2: XOFF character */ cd2401->u1.async.schr2 = t->c_cc[VSTOP]; /* * Special chars 3 and 4, char range, LNext, RFAR[1..4] and CRC * are unused, left as is. */ /* Set baudrates for receiver and transmitter */ cd2401->rbpr = (unsigned char)rx_period; cd2401->rcor = (unsigned char)(rx_period >> 8); /* no DPLL */ cd2401->tbpr = (unsigned char)tx_period; cd2401->tcor = (tx_period >> 3) & 0xE0; /* no x1 ext clk, no loopback */ /* Timeout for 4 chars at 9600, 8 bits per char, 1 stop bit */ cd2401->u2.w.rtpr = 0x04; /* NEED TO LOOK AT THIS LINE! */ if ( t->c_cflag & CREAD ) { /* Re-initialize channel, enable rx and tx */ cd2401_chan_cmd (minor, 0x2A, 1); /* Enable rx data ints */ cd2401->ier = 0x08; } else { /* Re-initialize channel, enable tx, disable rx */ cd2401_chan_cmd (minor, 0x29, 1); } } CD2401_RECORD_SET_ATTRIBUTES_INFO(( minor, need_reinitialization, csize, cstopb, parodd, parenb, ignpar, inpck, hw_flow_ctl, sw_flow_ctl, extra_flow_ctl, icrnl, igncr, inlcr, brkint, ignbrk, parmrk, istrip, tx_period, rx_period, out_baud, in_baud )); rtems_interrupt_enable (level); /* * Looks like the CD2401 needs time to settle after initialization. Give it * 10 ms. I don't really believe it, but if output resumes to quickly after * this call, the first few characters are not right. */ if ( need_reinitialization ) cd2401_udelay( 10000L ); /* Return something */ return RTEMS_SUCCESSFUL;}/* * cd2401_startRemoreTx * * Defined as a callback, but it would appear that it is never called. The * POSIX standard states that when the tcflow() function is called with the * TCION action, the system wall transmit a START character. Presumably, * tcflow() is called internally when IXOFF is set in the termios c_iflag * field when the input buffer can accomodate enough characters. It should * probably be called from fillBufferQueue(). Clearly, the function is also * explicitly callable by user code. The action is clearly to send the START * character, regardless of whether START/STOP flow control is in effect. * * Input parameters: * minor - selected channel * * Output parameters: NONE * * Return value: IGNORED * * PROPER START CHARACTER MUST BE PROGRAMMED IN SCHR1. */int cd2401_startRemoteTx( int minor){ rtems_interrupt_level level; rtems_interrupt_disable (level); cd2401->car = minor; /* Select channel */ cd2401->stcr = 0x01; /* Send SCHR1 ahead of chars in FIFO */ CD2401_RECORD_START_REMOTE_TX_INFO(( minor )); rtems_interrupt_enable (level); /* Return something */ return RTEMS_SUCCESSFUL;}/* * cd2401_stopRemoteTx * * Defined as a callback, but it would appear that it is never called. The * POSIX standard states that when the tcflow() function is called with the * TCIOFF function, the system wall transmit a STOP character. Presumably, * tcflow() is called internally when IXOFF is set in the termios c_iflag * field as the input buffer is about to overflow. It should probably be * called from rtems_termios_enqueue_raw_characters(). Clearly, the function * is also explicitly callable by user code. The action is clearly to send * the STOP character, regardless of whether START/STOP flow control is in * effect. * * Input parameters: * minor - selected channel * * Output parameters: NONE * * Return value: IGNORED * * PROPER STOP CHARACTER MUST BE PROGRAMMED IN SCHR2. */int cd2401_stopRemoteTx( int minor){ rtems_interrupt_level level; rtems_interrupt_disable (level); cd2401->car = minor; /* Select channel */ cd2401->stcr = 0x02; /* Send SCHR2 ahead of chars in FIFO */ CD2401_RECORD_STOP_REMOTE_TX_INFO(( minor )); rtems_interrupt_enable (level); /* Return something */ return RTEMS_SUCCESSFUL;}/* * cd2401_write * * Initiate DMA output. Termios guarantees that the buffer does not wrap * around, so we can do DMA strait from the supplied buffer. * * Input parameters: * minor - selected channel * buf - output buffer * len - number of chars to output * * Output parameters: NONE * * Return value: IGNORED * * MUST BE EXECUTED WITH THE CD2401 INTERRUPTS DISABLED! * The processor is placed at interrupt level CD2401_INT_LEVEL explicitly in * console_write(). The processor is necessarily at interrupt level 1 in * cd2401_tx_isr(). */int cd2401_write( int minor, const char *buf, int len){ cd2401->car = minor; /* Select channel */ if ( (cd2401->dmabsts & 0x08) == 0 ) { /* Next buffer is A. Wait for it to be ours. */ while ( cd2401->atbsts & 0x01 ); CD2401_Channel_Info[minor].own_buf_A = FALSE; CD2401_Channel_Info[minor].len = len; CD2401_Channel_Info[minor].buf = buf; cd2401->atbadru = (rtems_unsigned16)( ( (rtems_unsigned32) buf ) >> 16 ); cd2401->atbadrl = (rtems_unsigned16)( (rtems_unsigned32) buf ); cd2401->atbcnt = len; CD2401_RECORD_WRITE_INFO(( len, buf, 'A' )); cd2401->atbsts = 0x03; /* CD2401 owns buffer, int when empty */ } else { /* Next buffer is B. Wait for it to be ours. */ while ( cd2401->btbsts & 0x01 ); CD2401_Channel_Info[minor].own_buf_B = FALSE; CD2401_Channel_Info[minor].len = len; CD2401_Channel_Info[minor].buf = buf; cd2401->btbadru = (rtems_unsigned16)( ( (rtems_unsigned32) buf ) >> 16 ); cd2401->btbadrl = (rtems_unsigned16)( (rtems_unsigned32) buf ); cd2401->btbcnt = len; CD2401_RECORD_WRITE_INFO(( len, buf, 'B' )); cd2401->btbsts = 0x03; /* CD2401 owns buffer, int when empty */ } /* Nuts -- Need TxD ints */ CD2401_Channel_Info[minor].txEmpty = FALSE; cd2401->ier |= 0x01; /* Return something */ return RTEMS_SUCCESSFUL;}#if 0/* * cd2401_drainOutput * * Wait for the txEmpty indication on the specified channel. * * Input parameters: * minor - selected channel * * Output parameters: NONE * * Return value: IGNORED * * MUST NOT BE EXECUTED WITH THE CD2401 INTERRUPTS DISABLED! * The txEmpty flag is set by the tx ISR. * * DOES NOT WORK! DO NOT ENABLE THIS CODE. THE CD2401 DOES NOT COOPERATE! * The code is here to document that the output FIFO is NOT empty when * the CD2401 reports that the Tx buffer is empty. */int cd2401_drainOutput( int minor){ CD2401_RECORD_DRAIN_OUTPUT_INFO(( CD2401_Channel_Info[minor].txEmpty, CD2401_Channel_Info[minor].own_buf_A, CD2401_Channel_Info[minor].own_buf_B )); while( ! (CD2401_Channel_Info[minor].txEmpty && CD2401_Channel_Info[minor].own_buf_A && CD2401_Channel_Info[minor].own_buf_B) ); /* Return something */ return RTEMS_SUCCESSFUL;}#endif/* * _167Bug_pollRead * * Read a character from the 167Bug console, and return it. Return -1 * if there is no character in the input FIFO. * * Input parameters: * minor - selected channel * * Output parameters: NONE * * Return value: char returned as positive signed int * -1 if no character is present in the input FIFO. * * CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O! */int _167Bug_pollRead( int minor){ int char_not_available; unsigned char c; rtems_interrupt_level previous_level;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -