⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial_au1000.c

📁 MIPS下的boottloader yamon 的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 *  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 + -