📄 termiostty.c
字号:
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 + -