mirror of
https://github.com/UzixLS/picocom.git
synced 2025-07-19 07:21:18 +03:00
Workaround for drivers with broken flush
term_flush() does not work with some drivers. If we try to drain or even close the port while there are still data in it's output buffers *and* flow-control is enabled, we may block forever. So we "fake" a flush, by temporarily setting f/c to none, waiting for any data in the output buffer to drain, and then reseting f/c to it's original setting.
This commit is contained in:
10
picocom.c
10
picocom.c
@ -520,6 +520,16 @@ cleanup (int drain, int noreset)
|
||||
if ( drain )
|
||||
term_drain(tty_fd);
|
||||
term_flush(tty_fd);
|
||||
/* term_flush does not work with some drivers. If we try to
|
||||
drain or even close the port while there are still data in
|
||||
it's output buffers *and* flow-control is enabled we may
|
||||
block forever. So we "fake" a flush, by temporarily setting
|
||||
f/c to none, waiting for any data in the output buffer to
|
||||
drain, and then reseting f/c to it's original setting. If
|
||||
the real flush above does works, then the fake one should
|
||||
amount to instantaneously switching f/c to none and then
|
||||
back to its propper setting. */
|
||||
if ( opts.flow != FC_NONE ) term_fake_flush(tty_fd);
|
||||
term_set_hupcl(tty_fd, !noreset);
|
||||
term_apply(tty_fd, 1);
|
||||
if ( noreset ) {
|
||||
|
57
term.c
57
term.c
@ -1642,6 +1642,63 @@ term_drain(int fd)
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
int
|
||||
term_fake_flush(int fd)
|
||||
{
|
||||
struct termios tio;
|
||||
int rval, i, r;
|
||||
|
||||
rval = 0;
|
||||
|
||||
do { /* dummy */
|
||||
|
||||
i = term_find(fd);
|
||||
if ( i < 0 ) {
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get current termios */
|
||||
r = tcgetattr(fd, &tio);
|
||||
if ( r < 0 ) {
|
||||
term_errno = TERM_EGETATTR;
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
term.currtermios[i] = tio;
|
||||
/* Set flow-control to none */
|
||||
tio.c_cflag &= ~(CRTSCTS);
|
||||
tio.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||
/* Apply termios */
|
||||
r = tcsetattr(fd, TCSANOW, &tio);
|
||||
if ( r < 0 ) {
|
||||
term_errno = TERM_ESETATTR;
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
/* Wait for output to drain. Without flow-control this should
|
||||
complete in finite time. */
|
||||
r = tcdrain(fd);
|
||||
if ( r < 0 ) {
|
||||
term_errno = TERM_EDRAIN;
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
/* see comment in term_drain */
|
||||
if ( DRAIN_DELAY ) usleep(DRAIN_DELAY);
|
||||
/* Reset flow-control to original setting. */
|
||||
r = tcsetattr(fd, TCSANOW, &term.currtermios[i]);
|
||||
if ( r < 0 ) {
|
||||
term_errno = TERM_ESETATTR;
|
||||
rval = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (0);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
term_flush(int fd)
|
||||
{
|
||||
|
12
term.h
12
term.h
@ -65,6 +65,7 @@
|
||||
* F term_get_mctl - Get modem control signals status
|
||||
* F term_drain - drain the output from the terminal buffer
|
||||
* F term_flush - discard terminal input and output queue contents
|
||||
* F term_fake_flush - discard terminal input and output queue contents
|
||||
* F term_break - generate a break condition on a device
|
||||
* F term_baud_up - return next higher baudrate
|
||||
* F term_baud_down - return next lower baudrate
|
||||
@ -661,6 +662,17 @@ int term_drain (int fd);
|
||||
*/
|
||||
int term_flush (int fd);
|
||||
|
||||
/* F term_fake_flush
|
||||
*
|
||||
* Fake a term_flush, by temporarily configuring the device associated
|
||||
* with the managed fd to no flow-control and waiting until its output
|
||||
* queue drains.
|
||||
*
|
||||
* Returns negative on failure, non-negative on success.
|
||||
*/
|
||||
int term_fake_flush(int fd);
|
||||
|
||||
|
||||
/* F term_break
|
||||
*
|
||||
* This function generates a break condition on the device associated
|
||||
|
Reference in New Issue
Block a user