diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2016-05-26 13:39:31 -0400 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2016-05-26 13:39:31 -0400 |
commit | b62f1c15d20e58d87e8a26c2b151397ba98ae80d (patch) | |
tree | ebcf90d19b4132b43b48a17cf3be189e89240baf /serial.c | |
parent | c1b57c6d22b2b2ff49bc5bfd75fa49a888bd077e (diff) | |
download | gpsd-b62f1c15d20e58d87e8a26c2b151397ba98ae80d.tar.gz |
Attempting to solve tty mode prblems that have suraced sudenty.
Possibly temporary revert of close simplification, which looks like the culprit.
Diffstat (limited to 'serial.c')
-rw-r--r-- | serial.c | 35 |
1 files changed, 33 insertions, 2 deletions
@@ -216,7 +216,7 @@ speed_t gpsd_get_speed(const struct gps_device_t *dev) speed_t gpsd_get_speed_old(const struct gps_device_t *dev) { - return gpsd_get_speed_termios(&dev->ttyset); + return gpsd_get_speed_termios(&dev->ttyset_old); } char gpsd_get_parity(const struct gps_device_t *dev) @@ -551,6 +551,10 @@ int gpsd_serial_open(struct gps_device_t *session) session->lexer.type = BAD_PACKET; if ( 0 != isatty(session->gpsdata.gps_fd) && false == no_ttyset ) { + /* Save original terminal parameters */ + if (tcgetattr(session->gpsdata.gps_fd, &session->ttyset_old) != 0) + return UNALLOCATED_FD; + session->ttyset = session->ttyset_old; /* twiddle the speed, parity, etc. but only on real serial ports */ memset(session->ttyset.c_cc, 0, sizeof(session->ttyset.c_cc)); //session->ttyset.c_cc[VTIME] = 1; @@ -566,7 +570,7 @@ int gpsd_serial_open(struct gps_device_t *session) * over all devices. */ session->ttyset.c_cflag &= ~(PARENB | PARODD | CRTSCTS | CSTOPB); - session->ttyset.c_cflag |= CREAD | CLOCAL| HUPCL; + session->ttyset.c_cflag |= CREAD | CLOCAL; session->ttyset.c_iflag = session->ttyset.c_oflag = session->ttyset.c_lflag = (tcflag_t) 0; @@ -709,6 +713,33 @@ void gpsd_close(struct gps_device_t *session) (void)ioctl(session->gpsdata.gps_fd, (unsigned long)TIOCNXCL); #endif /* TIOCNXCL */ (void)tcdrain(session->gpsdata.gps_fd); + if (isatty(session->gpsdata.gps_fd) != 0) { + /* force hangup on close on systems that don't do HUPCL properly */ + (void)cfsetispeed(&session->ttyset, (speed_t) B0); + (void)cfsetospeed(&session->ttyset, (speed_t) B0); + (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW, + &session->ttyset); + } + /* this is the clean way to do it */ + session->ttyset_old.c_cflag |= HUPCL; + /* + * Don't revert the serial parameters if we didn't have to mess with + * them the first time. Economical, and avoids tripping over an + * obscure Linux 2.6 kernel bug that disables threaded + * ioctl(TIOCMWAIT) on a device after tcsetattr() is called. + */ + if (cfgetispeed(&session->ttyset_old) != cfgetispeed(&session->ttyset) || (session->ttyset_old.c_cflag & CSTOPB) != (session->ttyset.c_cflag & CSTOPB)) { + /* + * If we revert, keep the most recent baud rate. + * Cuts down on autobaud overhead the next time. + */ + (void)cfsetispeed(&session->ttyset_old, + (speed_t) session->gpsdata.dev.baudrate); + (void)cfsetospeed(&session->ttyset_old, + (speed_t) session->gpsdata.dev.baudrate); + (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW, + &session->ttyset_old); + } gpsd_log(&session->context->errout, LOG_SPIN, "SER: close(%d) in gpsd_close(%s)\n", session->gpsdata.gps_fd, session->gpsdata.dev.path); |