📄 serial_au1000.c
字号:
* If any character is present, it will be read into the user allocated
* variable; if none present, completion = 'ERROR_SERIAL_NO_CHARACTER'
* will be returned.
*
* Parameters :
* ------------
*
* 'major', IN, major device number
* 'minor', IN, minor device number for multi device drivers
* 'p_param', OUT, character read
*
* Return values :
* ---------------
* 'OK' = 0x00: character read into user variable
* 'ERROR_SERIAL_NO_CHARACTER': no character present on channel
* 'ERROR_SERIAL_COMM_ERROR': communication error detected
* 'ERROR_SERIAL_COMM_BREAK': 'BREAK' detected
*
************************************************************************/
static INT32
SERIAL_Au1000_read(
UINT32 major, /* IN: major device number */
UINT32 minor, /* IN: minor device number */
UINT8 *p_param ) /* OUT: character been read */
{
UINT32 rc;
UINT32 lstat;
UINT16 *getptr;
AU1X00_UART *uart = minor2base(minor);
/* check minor device number */
if(minor >= SERIAL_MAX_AU1x00_DEVICES)
{
return(ERROR_SERIAL_UNKNOWN_DEVICE);
}
SERIAL_Au1000_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 & ((UART_LINESTAT_OE<<8) |
(UART_LINESTAT_PE<<8) |
(UART_LINESTAT_FE<<8)))
{
if (rc == OK) rc = ERROR_SERIAL_COMM_ERROR ;
if (lstat & (UART_LINESTAT_OE<<8)) uart_statistics[minor].ua_rx_overrun++;
if (lstat & (UART_LINESTAT_PE<<8)) uart_statistics[minor].ua_rx_parity++;
if (lstat & (UART_LINESTAT_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] & UART_MDMCTRL_RT) == 0 &&
(((UINT32)getptr - (UINT32)recv_putptr[minor]) &
((POLLSIZE - 1) * sizeof(*getptr)))
>= HW_LIMIT_START * sizeof(*getptr) )
{
shadow_mcr[minor] |= UART_MDMCTRL_RT;
uart->mdmctrl = shadow_mcr[minor];
}
return( rc );
}
/************************************************************************
*
* SERIAL_Au1000_irqpoll
* Description :
* -------------
* Disabling of interrupts around call of SERIAL_Au1000_irq()
*
************************************************************************/
static UINT32
SERIAL_Au1000_irqpoll(
UINT32 minor )
{
UINT32 lstat;
#if 0
if(sys_disable_int())
{
lstat = SERIAL_Au1000_irq( minor, 0 );
sys_enable_int();
}
else
#endif
lstat = SERIAL_Au1000_irq( minor, 0 );
return lstat;
}
/************************************************************************
*
* SERIAL_Au1000_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_Au1000_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;
AU1X00_UART *uart = minor2base(minor);
putptr = recv_putptr[minor];
/* empty FIFO */
for (lstat = uart->linestat; lstat & UART_LINESTAT_DR; lstat = uart->linestat)
{
//rdata = PHY_RBR_R(minor) & 0xff;
rdata = uart->rxdata & 0xff;
uart_statistics[minor].ua_rx_irqs += in_intrpt;
if(lstat & UART_LINESTAT_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_mcr[minor] &= ~UART_MDMCTRL_RT;
uart->mdmctrl = shadow_mcr[minor];
}
if(room == 0)
{
lstat |= UART_LINESTAT_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_Au1000_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_Au1000_write(
UINT32 major, /* IN: major device number */
UINT32 minor, /* IN: minor device number */
UINT8 *p_param ) /* IN: pointer to character to write */
{
UINT32 lstat;
UINT8 mstat;
AU1X00_UART *uart = minor2base(minor);
/* check minor device number */
if(minor >= SERIAL_MAX_AU1x00_DEVICES)
{
return(ERROR_SERIAL_UNKNOWN_DEVICE);
}
/* check line status and modem status */
for (;;)
{
#if 0
/* enable this block to require UART3 CTS to be active before TXing data */
/* only UART3 of current Au1x00 chips has full modem control lines */
if (minor == SERIAL_MINOR_AU1x00_UART3) {
/* OBS: LSR_OE, LSR_PE, LSR_FE and LSR_BI are cleared on read */
if ( (SERIAL_Au1000_irqpoll(minor) & UART_LINESTAT_TT) &&
(uart->mdmstat & UART_MDMSTAT_CT))
break;
} else {
/* OBS: LSR_OE, LSR_PE, LSR_FE and LSR_BI are cleared on read */
if (SERIAL_Au1000_irqpoll(minor) & UART_LINESTAT_TT)
break;
}
#endif
/* OBS: LSR_OE, LSR_PE, LSR_FE and LSR_BI are cleared on read */
if (SERIAL_Au1000_irqpoll(minor) & UART_LINESTAT_TT)
break;
}
/* write character */
uart->txdata = *p_param;
uart_statistics[minor].ua_tx_bytes++;
return( OK );
}
/************************************************************************
*
* SERIAL_Au1000_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_Au1000_ctrl(
UINT32 major, /* IN: major device number */
UINT32 minor, /* IN: minor device number */
t_SERIAL_ctrl_descriptor *p_param ) /* INOUT: IOCTL structure */
{
UINT32 rcode;
AU1X00_UART *uart = minor2base(minor);
/* check minor device number */
if(minor >= SERIAL_MAX_AU1x00_DEVICES)
{
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_Au1000_irqpoll(minor); /* service UART */
if( (rcode = poll_retcode[minor]) != OK )
{
/* flush read buffer */
rcode = SERIAL_Au1000_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_Au1000_irqpoll( minor );
break;
case SERIAL_CTRL_RCV_IRQ:
SERIAL_Au1000_irq( minor, 1 );
break ;
case SERIAL_CTRL_RCV_IRQ_ON:
uart->inten =
shadow_ier[minor] = UART_INTEN_RIE;
break ;
case SERIAL_CTRL_RCV_IRQ_OFF:
uart->inten =
shadow_ier[minor] = 0;
break;
case SERIAL_CTRL_FORCE_DTR:
if (p_param->sc_arg.sc_dtr == 0)
shadow_mcr[minor] &= ~UART_MDMCTRL_DT;
else
shadow_mcr[minor] |= UART_MDMCTRL_DT;
uart->mdmctrl = shadow_mcr[minor];
break;
case SERIAL_CTRL_GET_MSR:
p_param->sc_arg.sc_msr = uart->mdmstat;
break;
case SERIAL_CTRL_SEND_BREAK:
uart->linectrl |= UART_LINECTRL_SB;
sys_wait_ms(250);
uart->linectrl &= ~UART_LINECTRL_SB;
break;
default:
rcode = ERROR_SERIAL_INVALID_ARGUMENT;
}
return( rcode );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -