From cd0e455a904160fe79ad6a0323d107e5be52262c Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Mon, 28 Aug 2006 21:17:01 +0000 Subject: [PATCH] Contributed by Ned Konz: Open the serial port with O_NONBLOCK, and save and restore the port state before exiting. patch #5008: Patch for (5.1) ser_posix.c for O_NONBLOCK open and restoring serial port state on close Closes bug #12622: avrdude hangs on macosx/darwin with PL-2303 usb-to-serial and Butterfly git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@627 81a1dc3b-b13d-400b-aceb-764788c761c2 --- ChangeLog | 10 +++++++++ ser_posix.c | 58 +++++++++++++++++++++++++++++++++++------------------ 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 08b07a2f..59eeba17 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2006-08-28 Joerg Wunsch + + Contributed by Ned Konz: + * ser_posix.c: Open the serial port with O_NONBLOCK, and + save and restore the port state before exiting. + patch #5008: Patch for (5.1) ser_posix.c for O_NONBLOCK open + and restoring serial port state on close + Closes bug #12622: avrdude hangs on macosx/darwin with PL-2303 + usb-to-serial and Butterfly + 2006-08-22 Joerg Wunsch * bitbang.c: Move the bitbang prerequisite checks out from diff --git a/ser_posix.c b/ser_posix.c index 990476ff..141fe782 100644 --- a/ser_posix.c +++ b/ser_posix.c @@ -1,6 +1,6 @@ /* * avrdude - A Downloader/Uploader for AVR device programmers - * Copyright (C) 2003-2004 Theodore A. Roth + * Copyright (C) 2003-2004, 2006 Theodore A. Roth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -65,6 +65,9 @@ static struct baud_mapping baud_lookup_table [] = { { 0, 0 } /* Terminator. */ }; +static struct termios original_termios; +static int saved_original_termios; + static speed_t serial_baud_lookup(long baud) { struct baud_mapping *map = baud_lookup_table; @@ -75,7 +78,7 @@ static speed_t serial_baud_lookup(long baud) map++; } - fprintf(stderr, "%s: serial_baud_lookup(): unknown baud rate: %ld", + fprintf(stderr, "%s: serial_baud_lookup(): unknown baud rate: %ld\n", progname, baud); exit(1); } @@ -87,43 +90,49 @@ static int ser_setspeed(int fd, long baud) speed_t speed = serial_baud_lookup (baud); if (!isatty(fd)) - return -1; + return -ENOTTY; /* * initialize terminal modes */ rc = tcgetattr(fd, &termios); if (rc < 0) { - fprintf(stderr, "%s: ser_setspeed(): tcgetattr() failed, %s", - progname, strerror(errno)); + fprintf(stderr, "%s: ser_setspeed(): tcgetattr() failed", + progname); return -errno; } - termios.c_iflag = 0; + /* + * copy termios for ser_close if we haven't already + */ + if (! saved_original_termios++) { + original_termios = termios; + } + + termios.c_iflag = IGNBRK; termios.c_oflag = 0; - termios.c_cflag = 0; - termios.c_cflag |= (CS8 | CREAD | CLOCAL); termios.c_lflag = 0; + termios.c_cflag = (CS8 | CREAD | CLOCAL); termios.c_cc[VMIN] = 1; termios.c_cc[VTIME] = 0; cfsetospeed(&termios, speed); cfsetispeed(&termios, speed); - rc = tcsetattr(fd, TCSANOW, &termios); + rc = tcsetattr(fd, TCSANOW | TCSAFLUSH, &termios); if (rc < 0) { - fprintf(stderr, "%s: ser_setspeed(): tcsetattr() failed, %s", - progname, strerror(errno)); + fprintf(stderr, "%s: ser_setspeed(): tcsetattr() failed", + progname); return -errno; } -#if 0 /* - * set non blocking mode + * Everything is now set up for a local line without modem control + * or flow control, so clear O_NONBLOCK again. */ rc = fcntl(fd, F_GETFL, 0); - fcntl(fd, F_SETFL, rc | O_NONBLOCK); -#endif + if (rc != -1) + fcntl(fd, F_SETFL, rc & ~O_NONBLOCK); return 0; } @@ -137,7 +146,7 @@ static int ser_open(char * port, long baud) /* * open the serial port */ - fd = open(port, O_RDWR | O_NOCTTY /*| O_NONBLOCK*/); + fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd < 0) { fprintf(stderr, "%s: ser_open(): can't open device \"%s\": %s\n", progname, port, strerror(errno)); @@ -150,8 +159,8 @@ static int ser_open(char * port, long baud) rc = ser_setspeed(fd, baud); if (rc) { fprintf(stderr, - "%s: ser_open(): can't set attributes for device \"%s\"\n", - progname, port); + "%s: ser_open(): can't set attributes for device \"%s\": %s\n", + progname, port, strerror(-rc)); exit(1); } @@ -161,7 +170,18 @@ static int ser_open(char * port, long baud) static void ser_close(int fd) { - /* FIXME: Should really restore the terminal to original state here. */ + /* + * restore original termios settings from ser_open + */ + if (saved_original_termios) { + int rc = tcsetattr(fd, TCSANOW | TCSADRAIN, &original_termios); + if (rc) { + fprintf(stderr, + "%s: ser_close(): can't reset attributes for device: %s\n", + progname, strerror(errno)); + } + saved_original_termios = 0; + } close(fd); }