/* TBD - move this to get_interrupt_type? */ void uart_hw_clear_interrupt(PUART_INFO uinfo) { #if (UART_16550) INBYTE(uinfo->port_base + LSR); /* clear status interrupt */ INBYTE(uinfo->port_base + MSR); #endif }
/* ******************************************************************** */ void uart_get_status(PUART_INFO uinfo, PUART_STATUS uart_status) { #if (UART_16550) byte msr; /* modem status register */ /* read the modem status register only once since reading it */ /* will clear it */ msr = INBYTE(uinfo->port_base + MSR); #if (UART_SUPPORTS_HANDSHAKING) uart_status->tx_handshake = (RTIP_BOOLEAN)(msr & uinfo->handshake_mask); #endif #if (INCLUDE_MODEM) if (uinfo->flags & MODEM_CONNECTED) { # if (DEBUG_MODEM) DEBUG_ERROR("check for MODEM DROP", NOVAR, 0, 0); # endif uart_status->modem_drop = (RTIP_BOOLEAN)(msr & UART_INV_DCD); if (uart_status->modem_drop) uinfo->flags &= ~MODEM_CONNECTED; } else { uart_status->modem_drop = FALSE; uinfo->flags |= MODEM_CONNECTED; } #endif #else #error: Implement checking if remote can recv or modem #endif }
/* Return TRUE if there is space in the UARTs registers to hold transmit data. Only called after a transmit or status interrupt happens. Return TRUE if there is space, FALSE if not. This is useful for when the UART has a FIFO that can be filled up multiple times on each tx interrupt. */ RTIP_BOOLEAN uart_hw_poll_tx(PUART_INFO uinfo) { #if (UART_16550) return ((RTIP_BOOLEAN)(INBYTE(uinfo->port_base + LSR) & LSR_TBE)); #else #error: Implement buffer checking for UART chip #endif }
/* Checks to see if the data buffer in the UART has any data in it. This is useful for UARTs with FIFOs, where one interrupt may fire because the FIFO is full. For UARTs with a one-byte FIFO, it suffices to just check and see if that's full. If your UART does not have any method for checking its data buffer, then something must be done. We do not support this condition yet. */ RTIP_BOOLEAN uart_hw_poll_rx(PUART_INFO uinfo) { #if (UART_16550) return ((RTIP_BOOLEAN)(INBYTE(uinfo->port_base + LSR) & LSR_RXRDY)); #else #error: Implement polling of the uart buffer #endif }
/* Read one byte of data from the uart, and return it. Is only called after a transmit interrupt fires (i.e. uart_hw_get_interrupt_type() returned UART_INPUT_INTERRUPT.) */ byte uart_hw_rx(PUART_INFO uinfo) { #if (UART_16550) return (byte) INBYTE(uinfo->port_base + RBR); #else #error: Implement retrieval of char from UART #endif }
RTIP_BOOLEAN uart_hw_needs_servicing(PUART_INFO uinfo) { #if (UART_16550) uinfo->int_id=(word)INBYTE(uinfo->port_base+IIR); return ((RTIP_BOOLEAN)((uinfo->int_id & 0x0001) == 0)); #else #error: Implement interrupt polling or turn off SUPPORTS_INT_POLLING #endif }
/* Implement this only if you will have handshaking capability in your UART. If you won't, then turn off UART_SUPPORTS_HANDSHAKING for your target. This function is */ void uart_hw_enable_sender(PUART_INFO uinfo) { #if (UART_16550) DEBUG_ERROR("ENABLE SENDER", NOVAR, 0, 0); OUTBYTE(uinfo->port_base + MCR, INBYTE(uinfo->port_base + MCR) | RESUME_MASK); #else #error Implement hw handshaking, rx enable, or turn off SUPPORTS_HANDSHAKING #endif }
/* 16550 is done with a macro in uartport.h */ void uart_hw_resume_sender(PUART_INFO uinfo) { #if (UART_16550) if (uinfo->handshake_mask) { OUTBYTE(uinfo->port_base + MCR, INBYTE(uinfo->port_base + MCR) | uinfo->resume_mask); io_delay(); } #else #error Implement hw handshaking, rx enable, or turn off SUPPORTS_HANDSHAKING #endif }
void uart_hw_hold_off_sender(PUART_INFO uinfo) { #if (UART_16550) if (uinfo->handshake_mask) { DEBUG_ERROR("HOLD OFF SENDER", NOVAR, 0, 0); OUTBYTE(uinfo->port_base + MCR, INBYTE(uinfo->port_base + MCR) & uinfo->holdoff_mask ); io_delay(); } #else #error Implement hw handshaking, rx enable, or turn off SUPPORTS_HANDSHAKING #endif }
/* Implement this only if you will have handshaking capability in your UART. If you won't, then turn off UART_SUPPORTS_HANDSHAKING for your target. This function should return TRUE if the remote host is ready to receive data, FALSE otherwise. This function is called from the ISR. */ RTIP_BOOLEAN uart_hw_poll_tx_handshake(PUART_INFO uinfo) { dword msr_reg; #if (UART_16550) /* return ((RTIP_BOOLEAN)(INBYTE(uinfo->port_base + MSR) & uinfo->handshake_mask)); */ msr_reg = INBYTE(uinfo->port_base + MSR); if (!(msr_reg & uinfo->handshake_mask)) { DEBUG_ERROR("uart_hw_poll_tx_handshake: msr, mask = ", DINT2, msr_reg, uinfo->handshake_mask); } return ((RTIP_BOOLEAN)(msr_reg & uinfo->handshake_mask)); #else #error Implement checking if remote can recv #endif }
int uart_hw_check_error(PUART_INFO uinfo) { #if (UART_16550) byte err_flag = (byte)(INBYTE(uinfo->port_base + LSR) & 0x1eu); if (err_flag) { if (err_flag & LS_OVRRUN_ERR) return 0; if (err_flag & LS_PARITY_ERR) return 1; if (err_flag & LS_FRAME_ERR) return 2; } io_delay(); return -1; #else #error: Implement checking error status #endif }
static void set_baud_rate(struct device *dev, u32_t baud_rate) { const struct uart_ns16550_device_config * const dev_cfg = DEV_CFG(dev); struct uart_ns16550_dev_data_t * const dev_data = DEV_DATA(dev); u32_t divisor; /* baud rate divisor */ u8_t lcr_cache; if ((baud_rate != 0) && (dev_cfg->sys_clk_freq != 0)) { /* calculate baud rate divisor */ divisor = (dev_cfg->sys_clk_freq / baud_rate) >> 4; /* set the DLAB to access the baud rate divisor registers */ lcr_cache = INBYTE(LCR(dev)); OUTBYTE(LCR(dev), LCR_DLAB | lcr_cache); OUTBYTE(BRDL(dev), (unsigned char)(divisor & 0xff)); OUTBYTE(BRDH(dev), (unsigned char)((divisor >> 8) & 0xff)); /* restore the DLAB to access the baud rate divisor registers */ OUTBYTE(LCR(dev), lcr_cache); dev_data->baud_rate = baud_rate; }
/* ******************************************************************** */ RTIP_BOOLEAN uart_hw_init(PUART_INFO uinfo) { #if (UART_16550) byte baud_rate_divisor; word port_base; byte comm_irq; byte temp_iir; #if (DONT_OPEN_UART) return(TRUE); #endif #if (UART_SUPPORTS_HANDSHAKING) if (uinfo->handshake_type == 'R') { #if (DEBUG_HANDSHAKING) DEBUG_ERROR("DOING R HANDSHAKING", NOVAR, 0, 0); #endif uinfo->handshake_mask = UART_CTS; uinfo->holdoff_mask = (byte)(~UART_RTS); uinfo->resume_mask = UART_RTS; } else if (uinfo->handshake_type == 'D') { uinfo->handshake_mask = UART_DSR; uinfo->holdoff_mask = (byte)(~UART_DTR); uinfo->resume_mask = UART_DTR; } else { uinfo->handshake_mask = 0; uinfo->holdoff_mask = (byte)(~UART_DTR); uinfo->resume_mask = UART_DTR; } #endif /* UART_SUPPORTS_HANDSHAKING */ switch (uinfo->comm_port) { case 1 : port_base = 0x3F8; /* I/O address for COM1 */ comm_irq = 4; /* IRQ for COM1 */ break; case 2 : port_base = 0x2F8; /* I/O address for COM2 */ comm_irq = 3; /* IRQ for COM2 */ break; case 3 : port_base = 0x3E8; /* I/O address for COM3 */ comm_irq = 4; /* IRQ for COM3 */ break; case 4 : port_base = 0x2E8; /* I/O address for COM4 */ comm_irq = 3; /* IRQ for COM4 */ break; default: DEBUG_ERROR("uart_hw_init: illegal comm port: ", EBS_INT1, uinfo->comm_port, 0); return(FALSE); } /* ****** */ /* convert baud rate to divisor and check if baud rate is valid */ switch (uinfo->baud_rate) { case 1152: baud_rate_divisor = 1; break; case 560: baud_rate_divisor = 2; break; case 384: baud_rate_divisor = 3; break; case 192: baud_rate_divisor = 6; break; case 96: baud_rate_divisor = 12; break; case 24: baud_rate_divisor = 48; break; case 12: baud_rate_divisor = 96; break; default: DEBUG_ERROR("uart_hw_init - bad baud rate = ", EBS_INT1, uinfo->baud_rate, 0); return(FALSE); /* set_errno(EBADBAUD); */ } /* Initialize UART */ /* interrupts were disabled already by the caller */ /* Set communication rate and parameters */ OUTBYTE(port_base + LCR, 0x80); /* divisor access */ io_delay(); OUTBYTE(port_base + BRDL, baud_rate_divisor); io_delay(); OUTBYTE(port_base + BRDH, 0); io_delay(); OUTBYTE(port_base + LCR, 0x03); /* divisor off, no parity, 1 stop bit, 8 bits */ io_delay(); /* Clear existing interrupts */ INBYTE(port_base + LSR); io_delay(); INBYTE(port_base + MSR); io_delay(); INBYTE(port_base + RBR); io_delay(); /* Enable FIFO with receive interrupt after 8 char */ OUTBYTE(port_base + FCR, 0x87); io_delay(); uinfo->xmit_fifo_size = 1; temp_iir = (byte)(INBYTE(port_base + IIR) & 0xf0); if (temp_iir == 0xc0) { DEBUG_ERROR("UART: 16550A", NOVAR, 0, 0); uinfo->is_16550=TRUE; uinfo->xmit_fifo_size = 16; } /* Enable read buffer full and receiver line status interrupts */ /* but not TX ints. Also enable modem status change INTS. */ OUTBYTE(port_base + IER, THRE_OFF); io_delay(); /* cause uart_interrupt to execute when interrupt occurs and */ /* uart_receive to be called by the interrupt task */ ks_hook_interrupt(comm_irq, (PFVOID) 0, (RTIPINTFN_POINTER)uart_interrupt, (RTIPINTFN_POINTER) 0, uinfo->minor_number); io_delay(); /* Enable interrupt signal and DTR */ OUTBYTE(port_base + MCR, 0x0b); io_delay(); uinfo->port_base=port_base; uinfo->comm_irq=comm_irq; #else #error: Set up any hardware dependent driver info here, and put it in UART_INFO #endif return(TRUE); }