Hi Everyone, I'm testing some software on DragonFly. There's not much to it. It talks to the modem, and sends an ATZ and then reads the response. Linux, FreeBSD, NetBSD, OpenBSD and OS X are OK.
My test rig is DragonFly 5.6-RELEASE x86_64 (fully patched) with a USR5637 modem, https://www.amazon.com/gp/product/B0013FDLM0. The modem is located at /dev/cuaU0. DragonFly hangs on the call to tcdrain(3). Looking at the man page I don't see any special handling. Cf., http://man.dragonflybsd.org/?command=tcdrain. Attached is the reproducer. The trace is: % ./test.exe Setting TIOCEXCL Getting tty Setting tty options Flushing tty Setting tty Writing ATZ Waiting for write <<-- call to tcdrain(fd) Thanks.
#include <stdlib.h> #include <stdio.h> #include <stddef.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include <termios.h> #include <sys/ioctl.h> #include <sys/stat.h> #if defined(__linux__) # define MODEM "/dev/ttyACM0" #elif defined(__APPLE__) # define MODEM "/dev/cu.usbmodem0000001" #elif defined(__NetBSD__) # define MODEM "/dev/dtyU0" #elif defined(__bsdi__) || defined(__DragonFly__) # define MODEM "/dev/cuaU0" #endif static void make_blocking(int fd) { const int old = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, old & ~(int)O_NONBLOCK); } static void make_nonblocking(int fd) { const int old = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, old | (int)O_NONBLOCK); } /* gcc -Wall -g3 -O1 -std=c99 test.c -o test.exe */ int main(int argc, char* argv[]) { int fd = open(MODEM, O_RDWR | O_NOCTTY | O_SYNC); if (fd == -1) { printf("open failed\n"); goto finish; } printf("Setting TIOCEXCL\n"); /* Mark the fd as exclusive so ModemManager */ /* and friends cannot open and muck with state. */ if (ioctl(fd, TIOCEXCL, NULL) == -1) { printf("ioctl failed\n"); goto finish; } printf("Getting tty\n"); struct termios tty; if (tcgetattr(fd, &tty) != 0) { printf("tcgetattr failed\n"); goto finish; } printf("Setting tty options\n"); cfmakeraw(&tty); tty.c_cflag |= (CLOCAL | CRTSCTS); // tty.c_cflag &= ~CSTOPB; /* 1 stop bit */ // tty.c_cflag |= CSTOPB; /* 2 stop bit */ cfsetospeed(&tty, B57600); cfsetispeed(&tty, B57600); printf("Flushing tty\n"); if (tcflush(fd, TCIOFLUSH) != 0) { printf("tcflush failed\n"); goto finish; } printf("Setting tty\n"); if (tcsetattr(fd, TCSANOW, &tty) != 0) { printf("tcsetattr failed\n"); goto finish; } /*********** Write ***********/ printf("Writing ATZ\n"); ssize_t res = write(fd, "ATZ\r", 4); if (res == -1) { printf("write failed\n"); goto finish; } printf("Waiting for write\n"); res = tcdrain(fd); if (res == -1) { printf("tcdrain failed\n"); goto finish; } printf("Wrote: ATZ\n"); /*********** Read ***********/ printf("Reading response\n"); make_blocking(fd); for ( ; ; ) { unsigned char buf[512]; res = read(fd, buf, sizeof(buf)); if (res == -1 && errno == EWOULDBLOCK) { break; } else if (res == -1) { printf("read failed\n"); goto finish; } make_nonblocking(fd); buf[res] = '\0'; printf("Read: %s\n", buf); } finish: if (fd != -1) close(fd); return 0; }