5 kx /* setserial.c - get/set Linux serial port info - rick sladkey */
5 kx /* modified to do work again and added setting fast serial speeds,
5 kx Michael K. Johnson, johnsonm@stolaf.edu */
5 kx /*
5 kx * Very heavily modified --- almost rewritten from scratch --- to have
5 kx * a more flexible command structure. Now able to set any of the
5 kx * serial-specific options using the TIOCSSERIAL ioctl().
5 kx * Theodore Ts'o, tytso@mit.edu, 1/1/93
5 kx *
5 kx * Last modified: [tytso:19940520.0036EDT]
5 kx */
5 kx
5 kx #include <stdio.h>
5 kx #include <stdlib.h>
5 kx #include <fcntl.h>
5 kx #include <termios.h>
5 kx #include <string.h>
5 kx #include <errno.h>
5 kx
5 kx #include <unistd.h>
5 kx #include <sys/ioctl.h>
5 kx
5 kx #ifdef HAVE_ASM_IOCTLS_H
5 kx #include <asm/ioctls.h>
5 kx #endif
5 kx #ifdef HAVE_LINUX_HAYESESP_H
5 kx #include <linux/hayesesp.h>
5 kx #endif
5 kx #include <linux/serial.h>
5 kx
5 kx #include "version.h"
5 kx
5 kx /*
5 kx http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git
5 kx a=commitdiff
5 kx h=f53a2ade0bb9f2a81f473e6469155172a96b7c38
5 kx */
5 kx #undef TIOCGHAYESESP
5 kx
5 kx static char version_str[] = "setserial version " SETSERIAL_VERSION ", "
5 kx SETSERIAL_DATE;
5 kx
5 kx char *progname;
5 kx
5 kx int verbosity = 1; /* 1 = normal, 0=boot-time, 2=everything */
5 kx /* -1 == arguments to setserial */
5 kx int verbose_flag = 0; /* print results after setting a port */
5 kx int quiet_flag = 0;
5 kx int zero_flag = 0;
5 kx
5 kx struct serial_type_struct {
5 kx int id;
5 kx char *name;
5 kx } serial_type_tbl[] = {
5 kx PORT_UNKNOWN, "unknown",
5 kx PORT_8250, "8250",
5 kx PORT_16450, "16450",
5 kx PORT_16550, "16550",
5 kx PORT_16550A, "16550A",
5 kx PORT_CIRRUS, "Cirrus",
5 kx PORT_16650, "16650",
5 kx PORT_16650V2, "16650V2",
5 kx PORT_16750, "16750",
5 kx PORT_16C950, "16950/954",
5 kx PORT_16C950, "16950",
5 kx PORT_16C950, "16954",
5 kx PORT_16654, "16654",
5 kx PORT_16850, "16850",
5 kx PORT_UNKNOWN, "none",
5 kx -1, NULL
5 kx };
5 kx
5 kx #define CMD_FLAG 1
5 kx #define CMD_PORT 2
5 kx #define CMD_IRQ 3
5 kx #define CMD_DIVISOR 4
5 kx #define CMD_TYPE 5
5 kx #define CMD_BASE 6
5 kx #define CMD_DELAY 7
5 kx #define CMD_WAIT 8
5 kx #define CMD_WAIT2 9
5 kx #define CMD_CONFIG 10
5 kx #define CMD_GETMULTI 11
5 kx #define CMD_SETMULTI 12
5 kx #define CMD_RX_TRIG 13
5 kx #define CMD_TX_TRIG 14
5 kx #define CMD_FLOW_OFF 15
5 kx #define CMD_FLOW_ON 16
5 kx #define CMD_RX_TMOUT 17
5 kx #define CMD_DMA_CHAN 18
5 kx
5 kx #define FLAG_CAN_INVERT 0x0001
5 kx #define FLAG_NEED_ARG 0x0002
5 kx
5 kx struct flag_type_table {
5 kx int cmd;
5 kx char *name;
5 kx int bits;
5 kx int mask;
5 kx int level;
5 kx int flags;
5 kx } flag_type_tbl[] = {
5 kx CMD_FLAG, "spd_normal", 0, ASYNC_SPD_MASK, 2, 0,
5 kx CMD_FLAG, "spd_hi", ASYNC_SPD_HI, ASYNC_SPD_MASK, 0, 0,
5 kx CMD_FLAG, "spd_vhi", ASYNC_SPD_VHI, ASYNC_SPD_MASK, 0, 0,
5 kx CMD_FLAG, "spd_shi", ASYNC_SPD_SHI, ASYNC_SPD_MASK, 0, 0,
5 kx CMD_FLAG, "spd_warp", ASYNC_SPD_WARP, ASYNC_SPD_MASK, 0, 0,
5 kx CMD_FLAG, "spd_cust", ASYNC_SPD_CUST, ASYNC_SPD_MASK, 0, 0,
5 kx
5 kx CMD_FLAG, "SAK", ASYNC_SAK, ASYNC_SAK, 0, FLAG_CAN_INVERT,
5 kx CMD_FLAG, "Fourport", ASYNC_FOURPORT, ASYNC_FOURPORT, 0, FLAG_CAN_INVERT,
5 kx CMD_FLAG, "hup_notify", ASYNC_HUP_NOTIFY, ASYNC_HUP_NOTIFY, 0, FLAG_CAN_INVERT,
5 kx CMD_FLAG, "skip_test", ASYNC_SKIP_TEST,ASYNC_SKIP_TEST,2, FLAG_CAN_INVERT,
5 kx CMD_FLAG, "auto_irq", ASYNC_AUTO_IRQ, ASYNC_AUTO_IRQ, 2, FLAG_CAN_INVERT,
5 kx CMD_FLAG, "split_termios", ASYNC_SPLIT_TERMIOS, ASYNC_SPLIT_TERMIOS, 2, FLAG_CAN_INVERT,
5 kx CMD_FLAG, "session_lockout", ASYNC_SESSION_LOCKOUT, ASYNC_SESSION_LOCKOUT, 2, FLAG_CAN_INVERT,
5 kx CMD_FLAG, "pgrp_lockout", ASYNC_PGRP_LOCKOUT, ASYNC_PGRP_LOCKOUT, 2, FLAG_CAN_INVERT,
5 kx CMD_FLAG, "callout_nohup", ASYNC_CALLOUT_NOHUP, ASYNC_CALLOUT_NOHUP, 2, FLAG_CAN_INVERT,
5 kx CMD_FLAG, "low_latency", ASYNC_LOW_LATENCY, ASYNC_LOW_LATENCY, 0, FLAG_CAN_INVERT,
5 kx CMD_PORT, "port", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_IRQ, "irq", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_DIVISOR, "divisor", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_TYPE, "uart", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_BASE, "base", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_BASE, "baud_base", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_DELAY, "close_delay", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_WAIT, "closing_wait", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_CONFIG, "autoconfig", 0, 0, 0, 0,
5 kx CMD_CONFIG, "autoconfigure",0, 0, 0, 0,
5 kx CMD_GETMULTI, "get_multiport",0, 0, 0, 0,
5 kx CMD_SETMULTI, "set_multiport",0, 0, 0, 0,
5 kx #ifdef TIOCGHAYESESP
5 kx CMD_RX_TRIG, "rx_trigger", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_TX_TRIG, "tx_trigger", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_FLOW_OFF, "flow_off", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_FLOW_ON, "flow_on", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_RX_TMOUT, "rx_timeout", 0, 0, 0, FLAG_NEED_ARG,
5 kx CMD_DMA_CHAN, "dma_channel", 0, 0, 0, FLAG_NEED_ARG,
5 kx #endif
5 kx 0, 0, 0, 0, 0, 0,
5 kx };
5 kx
5 kx char *serial_type(int id)
5 kx {
5 kx int i;
5 kx
5 kx for (i = 0; serial_type_tbl[i].id != -1; i++)
5 kx if (id == serial_type_tbl[i].id)
5 kx return serial_type_tbl[i].name;
5 kx return "undefined";
5 kx }
5 kx
5 kx int uart_type(char *name)
5 kx {
5 kx int i;
5 kx
5 kx for (i = 0; serial_type_tbl[i].id != -1; i++)
5 kx if (!strcasecmp(name, serial_type_tbl[i].name))
5 kx return serial_type_tbl[i].id;
5 kx return -1;
5 kx }
5 kx
5 kx
5 kx int atonum(char *s)
5 kx {
5 kx int n;
5 kx
5 kx while (*s == ' ')
5 kx s++;
5 kx if (strncmp(s, "0x", 2) == 0 || strncmp(s, "0X", 2) == 0)
5 kx sscanf(s + 2, "%x", &n);
5 kx else if (s[0] == '0' && s[1])
5 kx sscanf(s + 1, "%o", &n);
5 kx else
5 kx sscanf(s, "%d", &n);
5 kx return n;
5 kx }
5 kx
5 kx void print_flags(struct serial_struct *serinfo,
5 kx char *prefix, char *postfix)
5 kx {
5 kx struct flag_type_table *p;
5 kx int flags;
5 kx int first = 1;
5 kx
5 kx flags = serinfo->flags;
5 kx
5 kx for (p = flag_type_tbl; p->name; p++) {
5 kx if (p->cmd != CMD_FLAG)
5 kx continue;
5 kx if (verbosity == -1) {
5 kx if ((flags & p->mask) == p->bits)
5 kx printf(" %s", p->name);
5 kx continue;
5 kx }
5 kx if (verbosity < p->level)
5 kx continue;
5 kx if ((flags & p->mask) == p->bits) {
5 kx if (first) {
5 kx printf("%s", prefix);
5 kx first = 0;
5 kx } else
5 kx printf(" ");
5 kx printf("%s", p->name);
5 kx }
5 kx }
5 kx
5 kx if (!first)
5 kx printf("%s", postfix);
5 kx }
5 kx
5 kx #ifdef TIOCSERGETMULTI
5 kx void print_multiport(char *device, int fd)
5 kx {
5 kx struct serial_multiport_struct multi;
5 kx
5 kx if (ioctl(fd, TIOCSERGETMULTI, &multi) < 0)
5 kx return;
5 kx
5 kx if (!multi.port1 && !multi.port2 &&
5 kx !multi.port3 && !multi.port4 && !multi.port_monitor)
5 kx return;
5 kx
5 kx printf("%s", device);
5 kx if (multi.port_monitor)
5 kx printf(" port_monitor 0x%x", multi.port_monitor);
5 kx if (multi.port1)
5 kx printf(" port1 0x%x mask1 0x%x match1 0x%x", multi.port1,
5 kx multi.mask1, multi.match1);
5 kx if (multi.port2)
5 kx printf(" port2 0x%x mask2 0x%x match2 0x%x", multi.port2,
5 kx multi.mask2, multi.match2);
5 kx if (multi.port3)
5 kx printf(" port3 0x%x mask3 0x%x match3 0x%x", multi.port3,
5 kx multi.mask3, multi.match3);
5 kx if (multi.port4)
5 kx printf(" port4 0x%x mask4 0x%x match4 0x%x", multi.port4,
5 kx multi.mask4, multi.match4);
5 kx printf("\n");
5 kx }
5 kx
5 kx
5 kx void multiport_usage()
5 kx {
5 kx
5 kx fprintf(stderr, "\nValid keywords after set_multiport are:\n");
5 kx fprintf(stderr, "\tport_monitor, port[1-4], mask[1-4], "
5 kx "match[1-4]\n\n");
5 kx fprintf(stderr, "All arguments take an numeric argument following "
5 kx "the keyword.\n");
5 kx fprintf(stderr, "Use a leading '0x' for hex numbers.\n\n");
5 kx }
5 kx
5 kx void get_multiport(char *device, int fd)
5 kx {
5 kx struct serial_multiport_struct multi;
5 kx
5 kx if (ioctl(fd, TIOCSERGETMULTI, &multi) < 0) {
5 kx perror("Cannot get multiport config");
5 kx exit(1);
5 kx }
5 kx printf("Multiport config for irq %d:\n", multi.irq);
5 kx printf("\tPort monitor = 0x%x\n", multi.port_monitor);
5 kx printf("\tPort1 = 0x%x, mask=0x%x, match=0x%x\n", multi.port1,
5 kx multi.mask1, multi.match1);
5 kx printf("\tPort2 = 0x%x, mask=0x%x, match=0x%x\n", multi.port2,
5 kx multi.mask2, multi.match2);
5 kx printf("\tPort3 = 0x%x, mask=0x%x, match=0x%x\n", multi.port3,
5 kx multi.mask3, multi.match3);
5 kx printf("\tPort4 = 0x%x, mask=0x%x, match=0x%x\n", multi.port4,
5 kx multi.mask4, multi.match4);
5 kx }
5 kx
5 kx void set_multiport(char *device, int fd, char ***in_arg)
5 kx {
5 kx char **arg = *in_arg;
5 kx char *word, *argument;
5 kx struct serial_multiport_struct multi;
5 kx
5 kx if (ioctl(fd, TIOCSERGETMULTI, &multi) < 0) {
5 kx perror("Cannot get multiport config");
5 kx exit(1);
5 kx }
5 kx if (*arg == 0) {
5 kx multiport_usage();
5 kx return;
5 kx }
5 kx while (*arg) {
5 kx word = *arg++;
5 kx if (*arg == 0) {
5 kx multiport_usage();
5 kx exit(1);
5 kx }
5 kx argument = *arg++;
5 kx if (strcasecmp(word, "port_monitor") == 0) {
5 kx multi.port_monitor = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "port1") == 0) {
5 kx multi.port1 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "mask1") == 0) {
5 kx multi.mask1 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "match1") == 0) {
5 kx multi.match1 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "port2") == 0) {
5 kx multi.port2 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "mask2") == 0) {
5 kx multi.mask2 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "match2") == 0) {
5 kx multi.match2 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "port3") == 0) {
5 kx multi.port3 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "mask3") == 0) {
5 kx multi.mask3 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "match3") == 0) {
5 kx multi.match3 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "port4") == 0) {
5 kx multi.port4 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "mask4") == 0) {
5 kx multi.mask4 = atonum(argument);
5 kx continue;
5 kx }
5 kx if (strcasecmp(word, "match4") == 0) {
5 kx multi.match4 = atonum(argument);
5 kx continue;
5 kx }
5 kx fprintf(stderr, "Unknown keyword %s.\n", word);
5 kx multiport_usage();
5 kx exit(1);
5 kx }
5 kx if (ioctl(fd, TIOCSERSETMULTI, &multi) < 0) {
5 kx perror("Cannot set multiport config");
5 kx exit(1);
5 kx }
5 kx *in_arg = arg;
5 kx }
5 kx #else
5 kx void get_multiport(char *device, int fd)
5 kx {
5 kx printf("Setserial was compiled under a kernel which did not\n");
5 kx printf("support the special serial multiport configs.\n");
5 kx }
5 kx void set_multiport(char *device, int fd, char ***in_arg)
5 kx {
5 kx printf("Setserial was compiled under a kernel which did not\n");
5 kx printf("support the special serial multiport configs.\n");
5 kx }
5 kx #endif
5 kx
5 kx #ifdef TIOCGHAYESESP
5 kx void print_hayesesp(int fd)
5 kx {
5 kx struct hayes_esp_config esp;
5 kx
5 kx if (ioctl(fd, TIOCGHAYESESP, &esp) < 0)
5 kx return;
5 kx
5 kx printf("\tHayes ESP enhanced mode configuration:\n");
5 kx printf("\t\tRX trigger level: %d, TX trigger level: %d\n",
5 kx (int)esp.rx_trigger, (int)esp.tx_trigger);
5 kx printf("\t\tFlow off level: %d, Flow on level: %d\n",
5 kx (int)esp.flow_off, (int)esp.flow_on);
5 kx printf("\t\tRX timeout: %u, DMA channel: %d\n\n",
5 kx (unsigned int)esp.rx_timeout, (int)esp.dma_channel);
5 kx }
5 kx
5 kx void set_hayesesp(int fd, int cmd, int arg)
5 kx {
5 kx struct hayes_esp_config esp;
5 kx
5 kx if (ioctl(fd, TIOCGHAYESESP, &esp) < 0) {
5 kx printf("\nError: rx_trigger, tx_trigger, flow_off, "
5 kx "flow_on, rx_timeout, and dma_channel\n"
5 kx "are only valid for Hayes ESP ports.\n\n");
5 kx exit(1);
5 kx }
5 kx
5 kx switch (cmd) {
5 kx case CMD_RX_TRIG:
5 kx esp.rx_trigger = arg;
5 kx break;
5 kx case CMD_TX_TRIG:
5 kx esp.tx_trigger = arg;
5 kx break;
5 kx case CMD_FLOW_OFF:
5 kx esp.flow_off = arg;
5 kx break;
5 kx case CMD_FLOW_ON:
5 kx esp.flow_on = arg;
5 kx break;
5 kx case CMD_RX_TMOUT:
5 kx esp.rx_timeout = arg;
5 kx break;
5 kx case CMD_DMA_CHAN:
5 kx esp.dma_channel = arg;
5 kx break;
5 kx }
5 kx
5 kx if (ioctl(fd, TIOCSHAYESESP, &esp) < 0) {
5 kx printf("Cannot set Hayes ESP info\n");
5 kx exit(1);
5 kx }
5 kx }
5 kx #endif
5 kx
5 kx void get_serial(char *device)
5 kx {
5 kx struct serial_struct serinfo;
5 kx int fd;
5 kx char buf1[40];
5 kx
5 kx if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
5 kx perror(device);
5 kx return;
5 kx }
5 kx serinfo.reserved_char[0] = 0;
5 kx if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) {
5 kx perror("Cannot get serial info");
5 kx close(fd);
5 kx return;
5 kx }
5 kx if (serinfo.irq == 9)
5 kx serinfo.irq = 2; /* People understand 2 better than 9 */
5 kx if (verbosity==-1) {
5 kx printf("%s uart %s port 0x%.4x irq %d baud_base %d", device,
5 kx serial_type(serinfo.type), serinfo.port,
5 kx serinfo.irq, serinfo.baud_base);
5 kx print_flags(&serinfo, ", Flags: ", "");
5 kx printf("\n");
5 kx } else if (verbosity==2) {
5 kx printf("%s, Line %d, UART: %s, Port: 0x%.4x, IRQ: %d\n",
5 kx device, serinfo.line, serial_type(serinfo.type),
5 kx serinfo.port, serinfo.irq);
5 kx printf("\tBaud_base: %d, close_delay: %d, divisor: %d\n",
5 kx serinfo.baud_base, serinfo.close_delay,
5 kx serinfo.custom_divisor);
5 kx if (serinfo.closing_wait == ASYNC_CLOSING_WAIT_INF)
5 kx strcpy(buf1, "infinte");
5 kx else if (serinfo.closing_wait == ASYNC_CLOSING_WAIT_NONE)
5 kx strcpy(buf1, "none");
5 kx else
5 kx sprintf(buf1, "%d", serinfo.closing_wait);
5 kx printf("\tclosing_wait: %s\n", buf1);
5 kx print_flags(&serinfo, "\tFlags: ", "");
5 kx printf("\n\n");
5 kx
5 kx #ifdef TIOCGHAYESESP
5 kx print_hayesesp(fd);
5 kx #endif
5 kx } else if (verbosity==0) {
5 kx if (serinfo.type) {
5 kx printf("%s at 0x%.4x (irq = %d) is a %s",
5 kx device, serinfo.port, serinfo.irq,
5 kx serial_type(serinfo.type));
5 kx print_flags(&serinfo, " (", ")");
5 kx printf("\n");
5 kx }
5 kx } else {
5 kx printf("%s, UART: %s, Port: 0x%.4x, IRQ: %d",
5 kx device, serial_type(serinfo.type),
5 kx serinfo.port, serinfo.irq);
5 kx print_flags(&serinfo, ", Flags: ", "");
5 kx printf("\n");
5 kx }
5 kx close(fd);
5 kx }
5 kx
5 kx void set_serial(char *device, char ** arg)
5 kx {
5 kx struct serial_struct old_serinfo, new_serinfo;
5 kx struct flag_type_table *p;
5 kx int fd;
5 kx int do_invert = 0;
5 kx char *word;
5 kx
5 kx
5 kx if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
5 kx if (verbosity==0 && errno==ENOENT)
5 kx exit(201);
5 kx perror(device);
5 kx exit(201);
5 kx }
5 kx if (ioctl(fd, TIOCGSERIAL, &old_serinfo) < 0) {
5 kx perror("Cannot get serial info");
5 kx exit(1);
5 kx }
5 kx new_serinfo = old_serinfo;
5 kx if (zero_flag)
5 kx new_serinfo.flags = 0;
5 kx while (*arg) {
5 kx do_invert = 0;
5 kx word = *arg++;
5 kx if (*word == '^') {
5 kx do_invert++;
5 kx word++;
5 kx }
5 kx for (p = flag_type_tbl; p->name; p++) {
5 kx if (!strcasecmp(p->name, word))
5 kx break;
5 kx }
5 kx if (!p->name) {
5 kx fprintf(stderr, "Invalid flag: %s\n", word);
5 kx exit(1);
5 kx }
5 kx if (do_invert && !(p->flags & FLAG_CAN_INVERT)) {
5 kx fprintf(stderr, "This flag can not be inverted: %s\n", word);
5 kx exit(1);
5 kx }
5 kx if ((p->flags & FLAG_NEED_ARG) && !*arg) {
5 kx fprintf(stderr, "Missing argument for %s\n", word);
5 kx exit(1);
5 kx }
5 kx switch (p->cmd) {
5 kx case CMD_FLAG:
5 kx new_serinfo.flags &= ~p->mask;
5 kx if (!do_invert)
5 kx new_serinfo.flags |= p->bits;
5 kx break;
5 kx case CMD_PORT:
5 kx new_serinfo.port = atonum(*arg++);
5 kx break;
5 kx case CMD_IRQ:
5 kx new_serinfo.irq = atonum(*arg++);
5 kx break;
5 kx case CMD_DIVISOR:
5 kx new_serinfo.custom_divisor = atonum(*arg++);
5 kx break;
5 kx case CMD_TYPE:
5 kx new_serinfo.type = uart_type(*arg++);
5 kx if (new_serinfo.type < 0) {
5 kx fprintf(stderr, "Illegal UART type: %s", *--arg);
5 kx exit(1);
5 kx }
5 kx break;
5 kx case CMD_BASE:
5 kx new_serinfo.baud_base = atonum(*arg++);
5 kx break;
5 kx case CMD_DELAY:
5 kx new_serinfo.close_delay = atonum(*arg++);
5 kx break;
5 kx case CMD_WAIT:
5 kx if (!strcasecmp(*arg, "infinite"))
5 kx new_serinfo.closing_wait = ASYNC_CLOSING_WAIT_INF;
5 kx else if (!strcasecmp(*arg, "none"))
5 kx new_serinfo.closing_wait = ASYNC_CLOSING_WAIT_NONE;
5 kx else
5 kx new_serinfo.closing_wait = atonum(*arg);
5 kx arg++;
5 kx break;
5 kx case CMD_WAIT2:
5 kx if (!strcasecmp(*arg, "infinite"))
5 kx new_serinfo.closing_wait2 = ASYNC_CLOSING_WAIT_INF;
5 kx else if (!strcasecmp(*arg, "none"))
5 kx new_serinfo.closing_wait2 = ASYNC_CLOSING_WAIT_NONE;
5 kx else
5 kx new_serinfo.closing_wait2 = atonum(*arg);
5 kx arg++;
5 kx break;
5 kx case CMD_CONFIG:
5 kx if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
5 kx perror("Cannot set serial info");
5 kx exit(1);
5 kx }
5 kx if (ioctl(fd, TIOCSERCONFIG) < 0) {
5 kx perror("Cannot autoconfigure port");
5 kx exit(1);
5 kx }
5 kx if (ioctl(fd, TIOCGSERIAL, &new_serinfo) < 0) {
5 kx perror("Cannot get serial info");
5 kx exit(1);
5 kx }
5 kx break;
5 kx case CMD_GETMULTI:
5 kx if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
5 kx perror("Cannot set serial info");
5 kx exit(1);
5 kx }
5 kx get_multiport(device, fd);
5 kx break;
5 kx case CMD_SETMULTI:
5 kx if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
5 kx perror("Cannot set serial info");
5 kx exit(1);
5 kx }
5 kx set_multiport(device, fd, &arg);
5 kx break;
5 kx #ifdef TIOCGHAYESESP
5 kx case CMD_RX_TRIG:
5 kx case CMD_TX_TRIG:
5 kx case CMD_FLOW_OFF:
5 kx case CMD_FLOW_ON:
5 kx case CMD_RX_TMOUT:
5 kx case CMD_DMA_CHAN:
5 kx set_hayesesp(fd, p->cmd, atonum(*arg++));
5 kx break;
5 kx #endif
5 kx default:
5 kx fprintf(stderr, "Internal error: unhandled cmd #%d\n", p->cmd);
5 kx exit(1);
5 kx }
5 kx }
5 kx if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
5 kx perror("Cannot set serial info");
5 kx exit(1);
5 kx }
5 kx close(fd);
5 kx if (verbose_flag)
5 kx get_serial(device);
5 kx }
5 kx
5 kx void do_wild_intr(char *device)
5 kx {
5 kx int fd;
5 kx int i, mask;
5 kx int wild_mask = -1;
5 kx
5 kx if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
5 kx perror(device);
5 kx exit(1);
5 kx }
5 kx if (ioctl(fd, TIOCSERSWILD, &wild_mask) < 0) {
5 kx perror("Cannot scan for wild interrupts");
5 kx exit(1);
5 kx }
5 kx if (ioctl(fd, TIOCSERGWILD, &wild_mask) < 0) {
5 kx perror("Cannot get wild interrupt mask");
5 kx exit(1);
5 kx }
5 kx close(fd);
5 kx if (quiet_flag)
5 kx return;
5 kx if (wild_mask) {
5 kx printf("Wild interrupts found: ");
5 kx for (i=0, mask=1; mask <= wild_mask; i++, mask <<= 1)
5 kx if (mask & wild_mask)
5 kx printf(" %d", i);
5 kx printf("\n");
5 kx } else if (verbose_flag)
5 kx printf("No wild interrupts found.\n");
5 kx return;
5 kx }
5 kx
5 kx
5 kx
5 kx
5 kx void usage()
5 kx {
5 kx fprintf(stderr, "%s\n\n", version_str);
5 kx fprintf(stderr,
5 kx "usage:\t %s serial-device -abqvVWz [cmd1 [arg]] ... \n",
5 kx progname);
5 kx fprintf(stderr, "\t %s -g [-abGv] device1 ...\n\n", progname);
5 kx fprintf(stderr, "Available commands: (* = Takes an argument)\n");
5 kx fprintf(stderr, "\t\t(^ = can be preceded by a '^' to turn off the option)\n");
5 kx fprintf(stderr, "\t* port\t\tset the I/O port\n");
5 kx fprintf(stderr, "\t* irq\t\tset the interrupt\n");
5 kx fprintf(stderr, "\t* uart\t\tset UART type (none, 8250, 16450, 16550, 16550A,\n");
5 kx fprintf(stderr, "\t\t\t16650, 16650V2, 16750, 16850, 16950, 16954)\n");
5 kx fprintf(stderr, "\t* baud_base\tset base baud rate (CLOCK_FREQ / 16)\n");
5 kx fprintf(stderr, "\t* divisor\tset the custom divisor (see spd_custom)\n");
5 kx fprintf(stderr, "\t* close_delay\tset the amount of time (in 1/100 of a\n");
5 kx fprintf(stderr, "\t\t\t\tsecond) that DTR should be kept low\n");
5 kx fprintf(stderr, "\t\t\t\twhile being closed\n");
5 kx fprintf(stderr, "\t* closing_wait\tset the amount of time (in 1/100 of a\n");
5 kx fprintf(stderr, "\t\t\t\tsecond) that the serial port should wait for\n");
5 kx fprintf(stderr, "\t\t\t\tdata to be drained while being closed.\n");
5 kx fprintf(stderr, "\t^ fourport\tconfigure the port as an AST Fourport\n");
5 kx fprintf(stderr, "\t autoconfig\tautomatically configure the serial port\n");
5 kx fprintf(stderr, "\t^ auto_irq\ttry to determine irq during autoconfiguration\n");
5 kx fprintf(stderr, "\t^ skip_test\tskip UART test during autoconfiguration\n");
5 kx fprintf(stderr, "\n");
5 kx fprintf(stderr, "\t^ sak\t\tset the break key as the Secure Attention Key\n");
5 kx fprintf(stderr, "\t^ session_lockout Lock out callout port across different sessions\n");
5 kx fprintf(stderr, "\t^ pgrp_lockout\tLock out callout port across different process groups\n");
5 kx fprintf(stderr, "\t^ callout_nohup\tDon't hangup the tty when carrier detect drops\n");
5 kx fprintf(stderr, "\t\t\t\t on the callout device\n");
5 kx fprintf(stderr, "\t^ split_termios Use separate termios for callout and dailin lines\n");
5 kx fprintf(stderr, "\t^ hup_notify\tNotify a process blocked on opening a dial in line\n");
5 kx fprintf(stderr, "\t\t\t\twhen a process has finished using a callout\n");
5 kx fprintf(stderr, "\t\t\t\tline by returning EAGAIN to the open.\n");
5 kx fprintf(stderr, "\t^ low_latency\tMinimize receive latency at the cost of greater\n");
5 kx fprintf(stderr, "\t\t\t\tCPU utilization.\n");
5 kx fprintf(stderr, "\t get_multiport\tDisplay the multiport configuration\n");
5 kx fprintf(stderr, "\t set_multiport\tSet the multiport configuration\n");
5 kx fprintf(stderr, "\n");
5 kx #ifdef TIOCGHAYESESP
5 kx fprintf(stderr, "\t* rx_trigger\tSet RX trigger level (ESP-only)\n");
5 kx fprintf(stderr, "\t* tx_trigger\tSet TX trigger level (ESP-only)\n");
5 kx fprintf(stderr, "\t* flow_off\tSet hardware flow off level (ESP-only)\n");
5 kx fprintf(stderr, "\t* flow_on\tSet hardware flow on level (ESP-only)\n");
5 kx fprintf(stderr, "\t* rx_timeout\tSet receive timeout (ESP-only)\n");
5 kx fprintf(stderr, "\t* dma_channel\tSet DMA channel (ESP-only)\n");
5 kx #endif
5 kx fprintf(stderr, "\n");
5 kx fprintf(stderr, "\t spd_hi\tuse 56kb instead of 38.4kb\n");
5 kx fprintf(stderr, "\t spd_vhi\tuse 115kb instead of 38.4kb\n");
5 kx fprintf(stderr, "\t spd_shi\tuse 230kb instead of 38.4kb\n");
5 kx fprintf(stderr, "\t spd_warp\tuse 460kb instead of 38.4kb\n");
5 kx fprintf(stderr, "\t spd_cust\tuse the custom divisor to set the speed at 38.4kb\n");
5 kx fprintf(stderr, "\t\t\t\t(baud rate = baud_base / custom_divisor)\n");
5 kx fprintf(stderr, "\t spd_normal\tuse 38.4kb when a buad rate of 38.4kb is selected\n");
5 kx fprintf(stderr, "\n");
5 kx fprintf(stderr, "Use a leading '0x' for hex numbers.\n");
5 kx fprintf(stderr, "CAUTION: Using an invalid port can lock up your machine!\n");
5 kx exit(1);
5 kx }
5 kx
5 kx int main(int argc, char **argv)
5 kx {
5 kx int get_flag = 0, wild_intr_flag = 0;
5 kx int c;
5 kx extern int optind;
5 kx extern char *optarg;
5 kx
5 kx progname = argv[0];
5 kx if (argc == 1)
5 kx usage();
5 kx while ((c = getopt(argc, argv, "abgGqvVWz")) != EOF) {
5 kx switch (c) {
5 kx case 'a':
5 kx verbosity = 2;
5 kx break;
5 kx case 'b':
5 kx verbosity = 0;
5 kx break;
5 kx case 'q':
5 kx quiet_flag++;
5 kx break;
5 kx case 'v':
5 kx verbose_flag++;
5 kx break;
5 kx case 'g':
5 kx get_flag++;
5 kx break;
5 kx case 'G':
5 kx verbosity = -1;
5 kx break;
5 kx case 'V':
5 kx fprintf(stderr, "%s\n", version_str);
5 kx exit(0);
5 kx case 'W':
5 kx wild_intr_flag++;
5 kx break;
5 kx case 'z':
5 kx zero_flag++;
5 kx break;
5 kx default:
5 kx usage();
5 kx }
5 kx }
5 kx if (get_flag) {
5 kx argv += optind;
5 kx while (*argv)
5 kx get_serial(*argv++);
5 kx exit(0);
5 kx }
5 kx if (argc == optind)
5 kx usage();
5 kx if (wild_intr_flag) {
5 kx do_wild_intr(argv[optind]);
5 kx exit(0);
5 kx }
5 kx if (argc-optind == 1)
5 kx get_serial(argv[optind]);
5 kx else
5 kx set_serial(argv[optind], argv+optind+1);
5 kx exit(0);
5 kx }
5 kx