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

📄 termiostty.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
        xbuf[xbufsize++] = *buf;
        if ((xbufsize >= (WRITE_BUFSIZE-1)) || (input_bytes_read == *len) ||
            (*buf == '\n'))
        {
            cyg_int32 size = xbufsize;
            res = cyg_io_write(chan, xbuf, &size);
            if (res != ENOERR) {
                *len = input_bytes_read - (xbufsize - size);
                return res;
            }
            xbufsize = 0;
        }
        buf++;
    }
    // Everything sent, so *len is correct.
    return ENOERR;
}


//==========================================================================

static Cyg_ErrNo 
termios_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len)
{
    cyg_devtab_entry_t *dt = (cyg_devtab_entry_t *)handle;
    struct termios_private_info *priv = (struct termios_private_info *)dt->priv;
    cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
    struct termios *t = &priv->termios;
    cyg_uint32 clen;
    cyg_uint32 size;
    Cyg_ErrNo res;
    cyg_uint8 c;
    cyg_uint8 *buf = (cyg_uint8 *)_buf;
    cyg_bool discardc; // should c be discarded (not read, not printed)
    cyg_bool returnnow = false; // return back to user after this char
    
    // if receiver off
    if (0 == (t->c_cflag & CREAD) ) {
        *len = 0;
        return -EINVAL;
    }

    size = 0;
    if ( 0 == (t->c_lflag & ICANON) ) {
        // In non-canonical mode we return the min of *len and the
        // number of bytes available
        // So we query the driver for how many bytes are available - this
        // guarantees we won't block
        cyg_serial_buf_info_t dev_buf_conf;
        cyg_uint32 dbc_len = sizeof( dev_buf_conf );
        res = cyg_io_get_config( chan,
                                 CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO,
                                 &dev_buf_conf, &dbc_len );
        CYG_ASSERT( res == ENOERR, "Query buffer status failed!" );
        if (dev_buf_conf.rx_count > 0) {
            // Adjust length to be max characters currently available
            *len = *len < dev_buf_conf.rx_count ? *len : dev_buf_conf.rx_count;
        } else if (t->c_cc[VMIN] == 0) {
            // No chars available - don't block
            *len = 0;
            return ENOERR;
        }
    } // if

    while (!returnnow && size < *len) {
        clen = 1;
        discardc = false;
        res = cyg_io_read(chan, &c, &clen);
        if (res != ENOERR) {
            *len = size;
            return res;
        }

        // lock to prevent termios getting corrupted while we read from it
        cyg_drv_mutex_lock( &priv->lock );

        if ( t->c_iflag & ISTRIP )
            c &= 0x7f;

        // canonical mode: erase, kill, and newline processing
        if ( t->c_lflag & ICANON ) {
            if ( t->c_cc[ VERASE ] == c ) {
                discardc = true;
                // erase on display?
                if ( (t->c_lflag & ECHO) && (t->c_lflag & ECHOE) ) {
                    cyg_uint8 erasebuf[3];
                    erasebuf[0] = erasebuf[2] = t->c_cc[ VERASE ];
                    erasebuf[1] = ' ';
                    clen = sizeof(erasebuf);
                    // FIXME: what about error or non-blocking?
                    cyg_io_write(chan, erasebuf, &clen);
                }
                if ( size )
                    size--;
            } // if
            else if ( t->c_cc[ VKILL ] == c ) {
                // kill line on display?
                if ( (t->c_lflag & ECHO) && (t->c_lflag & ECHOK) ) {

                    // we could try and be more efficient here and 
                    // output a stream of erases, and then a stream
                    // of spaces and then more erases. But this is poor
                    // because on a slow terminal the user will see characters
                    // delete from the middle forward in chunks!
                    // But at least we try and chunk up sets of writes
                    cyg_uint8 erasebuf[30];
                    cyg_uint8 erasechunks;
                    cyg_uint8 i;

                    erasechunks = size < (sizeof(erasebuf)/3) ? 
                        size : (sizeof(erasebuf)/3);

                    for (i=0; i<erasechunks; i++) {
                        erasebuf[i*3] = erasebuf[i*3+2] = t->c_cc[ VERASE ];
                        erasebuf[i*3+1] = ' ';
                    }

                    while( size ) {
                        cyg_uint8 j;

                        j = size < (sizeof(erasebuf)/3) ? 
                            size : (sizeof(erasebuf)/3);
                        clen = (j*3);
                        // FIXME: what about error or non-blocking?
                        cyg_io_write( chan, erasebuf, &clen );
                        size -= j;
                    }
                } else
                    size = 0;
                discardc = true;
            } // else if
            // CR
            else if ( '\r' == c ) {
                if ( t->c_iflag & IGNCR )
                    discardc = true;
                else if ( t->c_iflag & ICRNL )
                    c = '\n';
            }
            // newlines or similar.
            // Note: not an else if to catch CRNL conversion
            if ( (t->c_cc[ VEOF ] == c) || (t->c_cc[ VEOL ] == c) ||
                 ('\n' == c) ) {
                if ( t->c_cc[ VEOF ] == c )
                     discardc = true;
                if ( t->c_lflag & ECHONL ) { // don't check ECHO in this case
                    clen = 1;
                    // FIXME: what about error or non-blocking?
                    // FIXME: what if INLCR is set?
                    cyg_io_write( chan, "\n", &clen );
                }
                if ( t->c_iflag & INLCR )
                    c = '\r';
                returnnow = true; // FIXME: true even for INLCR?
            } // else if
        } // if 

#ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
        if ( (t->c_lflag & ISIG) && (t->c_cc[ VINTR ] == c) ) {
            discardc = true;
            if ( 0 == (t->c_lflag & NOFLSH) )
                size = 0;
            // raise could be a non-local jump - we should unlock mutex
            cyg_drv_mutex_unlock( &priv->lock ); 

            // FIXME: what if raise returns != 0?
            raise( SIGINT );
            cyg_drv_mutex_lock( &priv->lock ); 
        } 

        if ( (t->c_lflag & ISIG) && (t->c_cc[ VQUIT ] == c) ) {
            discardc = true;
            if ( 0 == (t->c_lflag & NOFLSH) )
                size = 0;
            // raise could be a non-local jump - we should unlock mutex
            cyg_drv_mutex_unlock( &priv->lock ); 

            // FIXME: what if raise returns != 0?
            raise( SIGQUIT );
            cyg_drv_mutex_lock( &priv->lock ); 
        } 
#endif
        if (!discardc) {
            buf[size++] = c;
            if ( t->c_lflag & ECHO ) {
                clen = 1;
                // FIXME: what about error or non-blocking?
                termios_write( handle, &c, &clen );
            }
        }

        if ( (t->c_lflag & ICANON) == 0 ) {
            // Check to see if read has been satisfied
            if ( t->c_cc[ VMIN ] && (size >= t->c_cc[ VMIN ]) )
                returnnow = true;
        }
        cyg_drv_mutex_unlock( &priv->lock );
    } // while

    *len = size;
    return ENOERR;
}


//==========================================================================

static cyg_bool
termios_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
{
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
    struct termios_private_info *priv = (struct termios_private_info *)t->priv;
    cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;    

    // Just pass it on to next driver level
    return cyg_io_select( chan, which, info );
}


//==========================================================================

static Cyg_ErrNo 
termios_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf,
                   cyg_uint32 *len)
{
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
    struct termios_private_info *priv = (struct termios_private_info *)t->priv;
    cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
    Cyg_ErrNo res = ENOERR;

    switch (key) {
    case CYG_IO_GET_CONFIG_TERMIOS:
        {
            if ( *len < sizeof(struct termios) ) {
                return -EINVAL;
            }
            cyg_drv_mutex_lock( &priv->lock );
            *(struct termios *)buf = priv->termios;
            cyg_drv_mutex_unlock( &priv->lock );
            *len = sizeof(struct termios);
        }
        break;
    default:  // Assume this is a 'serial' driver control
        res = cyg_io_get_config(chan, key, buf, len);
    } // switch
    return res;
}


//==========================================================================


static Cyg_ErrNo 
termios_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf, cyg_uint32 *len)
{
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
    struct termios_private_info *priv = (struct termios_private_info *)t->priv;
    cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
    Cyg_ErrNo res = ENOERR;

    switch (key) {
    case CYG_IO_SET_CONFIG_TERMIOS:
        {
            setattr_struct *attr = (setattr_struct *)buf;
            int optact = attr->optact;

            if ( *len != sizeof( *attr ) ) {
                return -EINVAL;
            }

            CYG_ASSERT( (optact == TCSAFLUSH) || (optact == TCSADRAIN) ||
                        (optact == TCSANOW), "Invalid optact" );
                
            cyg_drv_mutex_lock( &priv->lock );
    
            if ( ( TCSAFLUSH == optact ) ||
                 ( TCSADRAIN == optact ) ) {
                res = cyg_io_get_config( chan,
                                         CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN,
                                         NULL, NULL );
                CYG_ASSERT( ENOERR == res, "Drain request failed" );
            }
            if ( TCSAFLUSH == optact ) {
                res = cyg_io_get_config( chan,
                                         CYG_IO_GET_CONFIG_SERIAL_INPUT_FLUSH,
                                         NULL, NULL );
                CYG_ASSERT( ENOERR == res, "Flush request failed" );
            }
                
            res = set_attr( attr->termios_p, priv );
            cyg_drv_mutex_unlock( &priv->lock );
            return res;
        }
    default: // Pass on to serial driver
        res = cyg_io_set_config(chan, key, buf, len);
    }
    return res;
}


//==========================================================================

#endif // ifdef CYGPKG_IO_SERIAL_TERMIOS

// EOF termiostty.c

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -