📄 serial_ti16550.c
字号:
UINT16 *getptr; /* check minor device number */ if(minor >= SERIAL_MAX_16550_DEVICES) { return(ERROR_SERIAL_UNKNOWN_DEVICE); } /* check for device initialization */ if( phy_lsr[minor] == NULL ) { return( ERROR_SERIAL_UNKNOWN_DEVICE ); } SERIAL_TI16550_irqpoll( minor ); /* service UART */ getptr= recv_getptr[minor]; if (getptr == recv_putptr[minor]) return( ERROR_SERIAL_NO_CHARACTER ); if (poll_retcode[minor] != OK) { poll_retcode[minor] = OK; /* flush receive buffer up to the last received ctrl/c or break */ getptr = recv_flushptr[minor]; /* always read CTRL/C in case of 'break' or ctrl/c */ lstat = (*getptr & 0xff00) | CTRL_C; rc = ERROR_SERIAL_COMM_BREAK; } else { lstat = *getptr; rc = OK; } *p_param = lstat; uart_statistics[minor].ua_rx_bytes++; /* check for errors */ if (lstat & ((SERIAL_LSR_OE<<8) | (SERIAL_LSR_PE<<8) | (SERIAL_LSR_FE<<8))) { if (rc == OK) rc = ERROR_SERIAL_COMM_ERROR ; if (lstat & (SERIAL_LSR_OE<<8)) uart_statistics[minor].ua_rx_overrun++; if (lstat & (SERIAL_LSR_PE<<8)) uart_statistics[minor].ua_rx_parity++; if (lstat & (SERIAL_LSR_FE<<8)) uart_statistics[minor].ua_rx_framing++; } if (++getptr >= &recv_buffer[minor][POLLSIZE]) getptr= &recv_buffer[minor][0]; recv_getptr[minor] = getptr; /* compute room in buffer */ if ( (shadow_mcr[minor] & SERIAL_MCR_RTS) == 0 && (((UINT32)getptr - (UINT32)recv_putptr[minor]) & ((POLLSIZE - 1) * sizeof(*getptr))) >= HW_LIMIT_START * sizeof(*getptr) ) { shadow_mcr[minor] |= SERIAL_MCR_RTS; PHY_MCR_W(minor, shadow_mcr[minor]); } return( rc );}/************************************************************************ * * SERIAL_TI16550_irqpoll * Description : * ------------- * Disabling of interrupts around call of SERIAL_TI16550_irq() * ************************************************************************/static UINT32 SERIAL_TI16550_irqpoll( UINT32 minor ){ UINT32 lstat; if(sys_disable_int()) { lstat = SERIAL_TI16550_irq( minor, 0 ); sys_enable_int(); } else lstat = SERIAL_TI16550_irq( minor, 0 ); return lstat;}/************************************************************************ * * SERIAL_TI16550_irq * Description : * ------------- * This service empties the UART's FIFO buffer and puts the chars into * the cyclic receive buffer. * * This routine is called in both polled and interrupt mode. * and requires interrupts to be disabled. * * static variables written: * poll_retcode BREAK or CTRL/C has been read * recv_putptr2 pointer to next free position in cyclic queue. * * static variables read: * phy_lsr pointer to UART line status register * phy_rbr pointer to UART receive data register * recv_getptr pointer to first unread position in cyclic queue. * recv_flushptr pointer to position of last read break or ctrl/c * ************************************************************************/static UINT32 SERIAL_TI16550_irq( UINT32 minor, UINT32 in_intrpt ){ UINT32 lstat; /* LSR_OE, LSR_PE, LSR_FE and LSR_BI are clear on read */ UINT8 rdata; UINT16 *putptr; UINT32 room; putptr = recv_putptr[minor]; /* empty FIFO */ for(lstat = PHY_LSR_R(minor); lstat & SERIAL_LSR_DR; lstat = PHY_LSR_R(minor)) { rdata = PHY_RBR_R(minor) & 0xff; uart_statistics[minor].ua_rx_irqs += in_intrpt; if(lstat & SERIAL_LSR_BI) { rdata = CTRL_C; uart_statistics[minor].ua_rx_break++; } /* compute room left in buffer, AFTER this byte has been put */ room = ((UINT32)recv_getptr[minor] - (UINT32)putptr - 1) & ((POLLSIZE - 1) * sizeof(*putptr)); if (room <= HW_LIMIT_STOP * sizeof(*putptr) && shadow_flow[minor] != 0) { shadow_mcr[minor] &= ~SERIAL_MCR_RTS; PHY_MCR_W(minor, shadow_mcr[minor]); } if(room == 0) { lstat |= SERIAL_LSR_OE; /* overrun */ /* overwrite previous char (overflow anyway) */ if (--putptr < &recv_buffer[minor][0]) putptr= &recv_buffer[minor][POLLSIZE-1]; } *putptr = (lstat << 8) | rdata; if(rdata == CTRL_C) { poll_retcode[minor] = ERROR_SERIAL_COMM_BREAK; recv_flushptr[minor] = putptr; } /* increase putptr to its future position */ if( ++putptr >= &recv_buffer[minor][POLLSIZE] ) putptr= &recv_buffer[minor][0]; } recv_putptr[minor] = putptr; return lstat;}/************************************************************************ * * SERIAL_TI16550_write * Description : * ------------- * This service writes a character on the specified channel * * Parameters : * ------------ * * 'major', IN, major device number * 'minor', IN, minor device number for multi device drivers * 'p_param', IN, pointer to character to write * * Return values : * --------------- * 'OK' = 0x00: character has been written on channel * ************************************************************************/static INT32 SERIAL_TI16550_write( UINT32 major, /* IN: major device number */ UINT32 minor, /* IN: minor device number */ UINT8 *p_param ) /* IN: pointer to character to write */{ /* check minor device number */ if(minor >= SERIAL_MAX_16550_DEVICES) { return(ERROR_SERIAL_UNKNOWN_DEVICE); } /* check for device initialization */ if( phy_lsr[minor] == NULL ) { return( ERROR_SERIAL_UNKNOWN_DEVICE ); } /* check line status and modem status */ for (;;) { /* OBS: LSR_OE, LSR_PE, LSR_FE and LSR_BI are cleared on read */ if ( (SERIAL_TI16550_irqpoll( minor ) & SERIAL_LSR_THRE) && ((PHY_MSR_R(minor) & SERIAL_MSR_CTS) || shadow_flow[minor] == 0)) break; } /* write character */ PHY_THR_W(minor, *p_param); uart_statistics[minor].ua_tx_bytes++; return( OK );}/************************************************************************ * * SERIAL_TI16550_ctrl * Description : * ------------- * This service performs the actions defined by t_SERIAL_ctrl_command_ids * on the specified channel. * * Parameters : * ------------ * * 'major', IN, major device number * 'minor', IN, minor device number for multi device drivers * 'p_param', INOUT, IOCTL structure * * Return values : * --------------- * 'OK' = 0x00: normal return * ERROR_SERIAL_COMM_BREAK: break or ctrl/c received * ERROR_SERIAL_COMM_ERROR: receive error, characters lost * ************************************************************************/static INT32 SERIAL_TI16550_ctrl( UINT32 major, /* IN: major device number */ UINT32 minor, /* IN: minor device number */ t_SERIAL_ctrl_descriptor *p_param ) /* INOUT: IOCTL structure */{ UINT32 rcode; /* check minor device number */ if(minor >= SERIAL_MAX_16550_DEVICES) { return(ERROR_SERIAL_UNKNOWN_DEVICE); } /* check for device initialization */ if( phy_lsr[minor] == NULL ) { return( ERROR_SERIAL_UNKNOWN_DEVICE ); } if(p_param == NULL) { return( ERROR_SERIAL_INVALID_ARGUMENT ); } rcode = OK; switch( p_param->sc_command ) { case SERIAL_CTRL_POLL_BREAK: SERIAL_TI16550_irqpoll(minor); /* service UART */ if( (rcode = poll_retcode[minor]) != OK ) { /* flush read buffer */ rcode = SERIAL_TI16550_read( major, minor, (UINT8 *)&rcode ); } break; case SERIAL_CTRL_GET_STATISTICS: memcpy((UINT8*)&p_param->sc_arg.sc_statistics, (UINT8 *)&uart_statistics[minor], sizeof(uart_statistics[minor])); break; case SERIAL_CTRL_GET_LSR: p_param->sc_arg.sc_linestat = SERIAL_TI16550_irqpoll( minor ); break; case SERIAL_CTRL_RCV_IRQ: SERIAL_TI16550_irq( minor, 1 ); break ; case SERIAL_CTRL_RCV_IRQ_ON: PHY_IER_W(minor, SERIAL_IER_RCVEN); shadow_ier[minor] = SERIAL_IER_RCVEN; break ; case SERIAL_CTRL_RCV_IRQ_OFF: shadow_ier[minor] = 0; PHY_IER_W(minor, 0); break; case SERIAL_CTRL_FORCE_DTR: if (p_param->sc_arg.sc_dtr == 0) shadow_mcr[minor] &= ~SERIAL_MCR_DTR; else shadow_mcr[minor] |= SERIAL_MCR_DTR; PHY_MCR_W(minor, shadow_mcr[minor]); break; case SERIAL_CTRL_GET_MSR: p_param->sc_arg.sc_msr = PHY_MSR_R(minor); break; case SERIAL_CTRL_SEND_BREAK: if (size[minor] == sizeof(UINT8)) { *(volatile UINT8*)(phy_lcr[minor]) |= SERIAL_LCR_BREAK; sys_wait_ms(250); *(volatile UINT8*)(phy_lcr[minor]) &= ~SERIAL_LCR_BREAK; } else { *(phy_lcr[minor]) |= SERIAL_LCR_BREAK; sys_wait_ms(250); *(phy_lcr[minor]) &= ~SERIAL_LCR_BREAK; } break; default: rcode = ERROR_SERIAL_INVALID_ARGUMENT; } return( rcode );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -