+/* --- @setconfig@ --- *
+ *
+ * Arguments: @txsu *tx@ = pointer to serial transport
+ * @serial_config *sc@ = pointer to configuration to set
+ *
+ * Returns: Zero if OK, nonzero on error.
+ *
+ * Use: Updates the external configuration from an internal
+ * representation.
+ */
+
+static int setconfig(txsu *tx, serial_config *sc)
+{
+ struct termios *ta = &tx->ta;
+ const struct baudmap *b;
+
+ for (b = baudmap; b->baud && b->baud != sc->baud; b++)
+ ;
+ if (!b->baud ||
+ sc->wordlen < 5 || sc->wordlen > 8 ||
+ sc->stopbits < 1 || sc->stopbits > 2) {
+ err_report(ERR_TXPORT, ERRTX_CONFIG, 0, "bad serial configuration");
+ return (-1);
+ }
+
+ ta->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
+ ta->c_oflag &= ~OPOST;
+ ta->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+ ta->c_cc[VMIN] = 1;
+ ta->c_cc[VTIME] = 0;
+
+ cfsetospeed(ta, b->magic);
+ cfsetispeed(ta, b->magic);
+ ta->c_cflag = (ta->c_cflag & ~CSIZE) | csize[sc->wordlen - 5];
+ switch (sc->parity) {
+ case PARITY_NONE: ta->c_cflag &= ~PARENB; break;
+ case PARITY_ODD: ta->c_cflag |= PARENB | PARODD; break;
+ case PARITY_EVEN: ta->c_cflag |= PARENB; ta->c_cflag &= ~PARODD; break;
+ }
+ switch (sc->stopbits) {
+ case 1: ta->c_cflag &= ~CSTOPB; break;
+ case 2: ta->c_cflag |= CSTOPB; break;
+ }
+
+ switch (sc->flow) {
+ case FLOW_NONE:
+ ta->c_cflag &= ~CRTSCTS;
+ ta->c_iflag &= ~(IXON | IXOFF);
+ break;
+ case FLOW_XONXOFF:
+ ta->c_cflag &= ~CRTSCTS;
+ ta->c_iflag |= IXON | IXOFF;
+ break;
+ case FLOW_RTSCTS:
+ ta->c_cflag |= CRTSCTS;
+ ta->c_iflag &= ~(IXON | IXOFF);
+ break;
+ }
+
+ if (tcsetattr(tx->fd, TCSAFLUSH, ta)) {
+ err_report(ERR_TXPORT, ERRTX_CREATE, errno,
+ "couldn't set terminal attributes: %s", strerror(errno));
+ return (-1);
+ }
+
+ tx->sc = *sc;
+ return (0);
+}
+