Fixes (mostly from Colin Watson, a couple redone by me) to make Unix
[u/mdw/putty] / unix / uxser.c
index 85e9618..2155b92 100644 (file)
@@ -2,12 +2,6 @@
  * Serial back end (Unix-specific).
  */
 
-/*
- * TODO:
- * 
- *  - send break.
- */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
@@ -135,9 +129,51 @@ static const char *serial_configure(Serial serial, Config *cfg)
 #ifdef B115200
     CHECKBAUD(115200);
 #endif
+#ifdef B153600
+    CHECKBAUD(153600);
+#endif
 #ifdef B230400
     CHECKBAUD(230400);
 #endif
+#ifdef B307200
+    CHECKBAUD(307200);
+#endif
+#ifdef B460800
+    CHECKBAUD(460800);
+#endif
+#ifdef B500000
+    CHECKBAUD(500000);
+#endif
+#ifdef B576000
+    CHECKBAUD(576000);
+#endif
+#ifdef B921600
+    CHECKBAUD(921600);
+#endif
+#ifdef B1000000
+    CHECKBAUD(1000000);
+#endif
+#ifdef B1152000
+    CHECKBAUD(1152000);
+#endif
+#ifdef B1500000
+    CHECKBAUD(1500000);
+#endif
+#ifdef B2000000
+    CHECKBAUD(2000000);
+#endif
+#ifdef B2500000
+    CHECKBAUD(2500000);
+#endif
+#ifdef B3000000
+    CHECKBAUD(3000000);
+#endif
+#ifdef B3500000
+    CHECKBAUD(3500000);
+#endif
+#ifdef B4000000
+    CHECKBAUD(4000000);
+#endif
 #undef CHECKBAUD
 #undef SETBAUD
     cfsetispeed(&options, bflag);
@@ -168,9 +204,15 @@ static const char *serial_configure(Serial serial, Config *cfg)
     logevent(serial->frontend, msg);
     sfree(msg);
 
-    options.c_cflag &= ~(IXON|IXOFF);
+    options.c_iflag &= ~(IXON|IXOFF);
+#ifdef CRTSCTS
+    options.c_cflag &= ~CRTSCTS;
+#endif
+#ifdef CNEW_RTSCTS
+    options.c_cflag &= ~CNEW_RTSCTS;
+#endif
     if (cfg->serflow == SER_FLOW_XONXOFF) {
-       options.c_cflag |= IXON | IXOFF;
+       options.c_iflag |= IXON | IXOFF;
        str = "XON/XOFF";
     } else if (cfg->serflow == SER_FLOW_RTSCTS) {
 #ifdef CRTSCTS
@@ -205,7 +247,25 @@ static const char *serial_configure(Serial serial, Config *cfg)
 
     options.c_cflag |= CLOCAL | CREAD;
     options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
-    options.c_oflag &= ~OPOST;
+    options.c_iflag &= ~(ISTRIP | IGNCR | INLCR | ICRNL
+#ifdef IUCLC
+                        | IUCLC
+#endif
+                        );
+    options.c_oflag &= ~(OPOST
+#ifdef ONLCR
+                        | ONLCR
+#endif
+#ifdef OCRNL
+                        | OCRNL
+#endif
+#ifdef ONOCR
+                        | ONOCR
+#endif
+#ifdef ONLRET
+                        | ONLRET
+#endif
+                        );
     options.c_cc[VMIN] = 1;
     options.c_cc[VTIME] = 0;
 
@@ -248,6 +308,8 @@ static const char *serial_init(void *frontend_handle, void **backend_handle,
     if (serial->fd < 0)
        return "Unable to open serial port";
 
+    cloexec(serial->fd);
+
     err = serial_configure(serial, cfg);
     if (err)
        return err;
@@ -260,6 +322,11 @@ static const char *serial_init(void *frontend_handle, void **backend_handle,
 
     serial_uxsel_setup(serial);
 
+    /*
+     * Specials are always available.
+     */
+    update_specials_menu(serial->frontend);
+
     return NULL;
 }
 
@@ -285,13 +352,11 @@ static void serial_free(void *handle)
 static void serial_reconfig(void *handle, Config *cfg)
 {
     Serial serial = (Serial) handle;
-    const char *err;
-
-    err = serial_configure(serial, cfg);
 
     /*
-     * FIXME: what should we do if err returns something?
+     * FIXME: what should we do if this returns an error?
      */
+    serial_configure(serial, cfg);
 }
 
 static int serial_select_result(int fd, int event)
@@ -317,6 +382,14 @@ static int serial_select_result(int fd, int event)
             */
            finished = TRUE;
        } else if (ret < 0) {
+#ifdef EAGAIN
+           if (errno == EAGAIN)
+               return 1;              /* spurious */
+#endif
+#ifdef EWOULDBLOCK
+           if (errno == EWOULDBLOCK)
+               return 1;              /* spurious */
+#endif
            perror("read serial port");
            exit(1);
        } else if (ret > 0) {
@@ -418,9 +491,13 @@ static void serial_size(void *handle, int width, int height)
  */
 static void serial_special(void *handle, Telnet_Special code)
 {
-    /*
-     * FIXME: serial break? XON? XOFF?
-     */
+    Serial serial = (Serial) handle;
+
+    if (serial->fd >= 0 && code == TS_BRK) {
+       tcsendbreak(serial->fd, 0);
+       logevent(serial->frontend, "Sending serial break at user request");
+    }
+
     return;
 }
 
@@ -430,10 +507,11 @@ static void serial_special(void *handle, Telnet_Special code)
  */
 static const struct telnet_special *serial_get_specials(void *handle)
 {
-    /*
-     * FIXME: serial break? XON? XOFF?
-     */
-    return NULL;
+    static const struct telnet_special specials[] = {
+       {"Break", TS_BRK},
+       {NULL, TS_EXITMENU}
+    };
+    return specials;
 }
 
 static int serial_connected(void *handle)
@@ -506,5 +584,7 @@ Backend serial_backend = {
     serial_provide_logctx,
     serial_unthrottle,
     serial_cfg_info,
-    1
+    "serial",
+    PROT_SERIAL,
+    0
 };