1 /* setserial.c - get/set Linux serial port info - rick sladkey */
2 /* modified to do work again and added setting fast serial speeds,
3 Michael K. Johnson, johnsonm@stolaf.edu */
5 * Very heavily modified --- almost rewritten from scratch --- to have
6 * a more flexible command structure. Now able to set any of the
7 * serial-specific options using the TIOCSSERIAL ioctl().
8 * Theodore Ts'o, tytso@mit.edu, 1/1/93
10 * Last modified: [tytso:19940520.0036EDT]
19 #ifdef HAVE_ASM_IOCTLS_H
20 #include <asm/ioctls.h>
22 #ifdef HAVE_LINUX_HAYESESP_H
23 #include <linux/hayesesp.h>
25 #include <linux/serial.h>
29 static char version_str[] = "setserial version " SETSERIAL_VERSION ", "
34 int verbosity = 1; /* 1 = normal, 0=boot-time, 2=everything */
35 /* -1 == arguments to setserial */
36 int verbose_flag = 0; /* print results after setting a port */
40 struct serial_type_struct {
43 } serial_type_tbl[] = {
44 PORT_UNKNOWN, "unknown",
48 PORT_16550A, "16550A",
49 PORT_CIRRUS, "Cirrus",
51 PORT_16650V2, "16650V2",
54 PORT_16C950, "16950/954",
78 #define CMD_GETMULTI 11
79 #define CMD_SETMULTI 12
80 #define CMD_RX_TRIG 13
81 #define CMD_TX_TRIG 14
82 #define CMD_FLOW_OFF 15
83 #define CMD_FLOW_ON 16
84 #define CMD_RX_TMOUT 17
85 #define CMD_DMA_CHAN 18
87 #define FLAG_CAN_INVERT 0x0001
88 #define FLAG_NEED_ARG 0x0002
90 struct flag_type_table {
98 CMD_FLAG, "spd_normal", 0, ASYNC_SPD_MASK, 2, 0,
99 CMD_FLAG, "spd_hi", ASYNC_SPD_HI, ASYNC_SPD_MASK, 0, 0,
100 CMD_FLAG, "spd_vhi", ASYNC_SPD_VHI, ASYNC_SPD_MASK, 0, 0,
101 CMD_FLAG, "spd_shi", ASYNC_SPD_SHI, ASYNC_SPD_MASK, 0, 0,
102 CMD_FLAG, "spd_warp", ASYNC_SPD_WARP, ASYNC_SPD_MASK, 0, 0,
103 CMD_FLAG, "spd_cust", ASYNC_SPD_CUST, ASYNC_SPD_MASK, 0, 0,
105 CMD_FLAG, "SAK", ASYNC_SAK, ASYNC_SAK, 0, FLAG_CAN_INVERT,
106 CMD_FLAG, "Fourport", ASYNC_FOURPORT, ASYNC_FOURPORT, 0, FLAG_CAN_INVERT,
107 CMD_FLAG, "hup_notify", ASYNC_HUP_NOTIFY, ASYNC_HUP_NOTIFY, 0, FLAG_CAN_INVERT,
108 CMD_FLAG, "skip_test", ASYNC_SKIP_TEST,ASYNC_SKIP_TEST,2, FLAG_CAN_INVERT,
109 CMD_FLAG, "auto_irq", ASYNC_AUTO_IRQ, ASYNC_AUTO_IRQ, 2, FLAG_CAN_INVERT,
110 CMD_FLAG, "split_termios", ASYNC_SPLIT_TERMIOS, ASYNC_SPLIT_TERMIOS, 2, FLAG_CAN_INVERT,
111 CMD_FLAG, "session_lockout", ASYNC_SESSION_LOCKOUT, ASYNC_SESSION_LOCKOUT, 2, FLAG_CAN_INVERT,
112 CMD_FLAG, "pgrp_lockout", ASYNC_PGRP_LOCKOUT, ASYNC_PGRP_LOCKOUT, 2, FLAG_CAN_INVERT,
113 CMD_FLAG, "callout_nohup", ASYNC_CALLOUT_NOHUP, ASYNC_CALLOUT_NOHUP, 2, FLAG_CAN_INVERT,
114 CMD_FLAG, "low_latency", ASYNC_LOW_LATENCY, ASYNC_LOW_LATENCY, 0, FLAG_CAN_INVERT,
115 CMD_PORT, "port", 0, 0, 0, FLAG_NEED_ARG,
116 CMD_IRQ, "irq", 0, 0, 0, FLAG_NEED_ARG,
117 CMD_DIVISOR, "divisor", 0, 0, 0, FLAG_NEED_ARG,
118 CMD_TYPE, "uart", 0, 0, 0, FLAG_NEED_ARG,
119 CMD_BASE, "base", 0, 0, 0, FLAG_NEED_ARG,
120 CMD_BASE, "baud_base", 0, 0, 0, FLAG_NEED_ARG,
121 CMD_DELAY, "close_delay", 0, 0, 0, FLAG_NEED_ARG,
122 CMD_WAIT, "closing_wait", 0, 0, 0, FLAG_NEED_ARG,
123 CMD_CONFIG, "autoconfig", 0, 0, 0, 0,
124 CMD_CONFIG, "autoconfigure",0, 0, 0, 0,
125 CMD_GETMULTI, "get_multiport",0, 0, 0, 0,
126 CMD_SETMULTI, "set_multiport",0, 0, 0, 0,
128 CMD_RX_TRIG, "rx_trigger", 0, 0, 0, FLAG_NEED_ARG,
129 CMD_TX_TRIG, "tx_trigger", 0, 0, 0, FLAG_NEED_ARG,
130 CMD_FLOW_OFF, "flow_off", 0, 0, 0, FLAG_NEED_ARG,
131 CMD_FLOW_ON, "flow_on", 0, 0, 0, FLAG_NEED_ARG,
132 CMD_RX_TMOUT, "rx_timeout", 0, 0, 0, FLAG_NEED_ARG,
133 CMD_DMA_CHAN, "dma_channel", 0, 0, 0, FLAG_NEED_ARG,
138 char *serial_type(int id)
142 for (i = 0; serial_type_tbl[i].id != -1; i++)
143 if (id == serial_type_tbl[i].id)
144 return serial_type_tbl[i].name;
148 int uart_type(char *name)
152 for (i = 0; serial_type_tbl[i].id != -1; i++)
153 if (!strcasecmp(name, serial_type_tbl[i].name))
154 return serial_type_tbl[i].id;
165 if (strncmp(s, "0x", 2) == 0 || strncmp(s, "0X", 2) == 0)
166 sscanf(s + 2, "%x", &n);
167 else if (s[0] == '0' && s[1])
168 sscanf(s + 1, "%o", &n);
174 void print_flags(struct serial_struct *serinfo,
175 char *prefix, char *postfix)
177 struct flag_type_table *p;
181 flags = serinfo->flags;
183 for (p = flag_type_tbl; p->name; p++) {
184 if (p->cmd != CMD_FLAG)
186 if (verbosity == -1) {
187 if ((flags & p->mask) == p->bits)
188 printf(" %s", p->name);
191 if (verbosity < p->level)
193 if ((flags & p->mask) == p->bits) {
195 printf("%s", prefix);
199 printf("%s", p->name);
204 printf("%s", postfix);
207 #ifdef TIOCSERGETMULTI
208 void print_multiport(char *device, int fd)
210 struct serial_multiport_struct multi;
212 if (ioctl(fd, TIOCSERGETMULTI, &multi) < 0)
215 if (!multi.port1 && !multi.port2 &&
216 !multi.port3 && !multi.port4 && !multi.port_monitor)
219 printf("%s", device);
220 if (multi.port_monitor)
221 printf(" port_monitor 0x%x", multi.port_monitor);
223 printf(" port1 0x%x mask1 0x%x match1 0x%x", multi.port1,
224 multi.mask1, multi.match1);
226 printf(" port2 0x%x mask2 0x%x match2 0x%x", multi.port2,
227 multi.mask2, multi.match2);
229 printf(" port3 0x%x mask3 0x%x match3 0x%x", multi.port3,
230 multi.mask3, multi.match3);
232 printf(" port4 0x%x mask4 0x%x match4 0x%x", multi.port4,
233 multi.mask4, multi.match4);
238 void multiport_usage()
241 fprintf(stderr, "\nValid keywords after set_multiport are:\n");
242 fprintf(stderr, "\tport_monitor, port[1-4], mask[1-4], "
244 fprintf(stderr, "All arguments take an numeric argument following "
246 fprintf(stderr, "Use a leading '0x' for hex numbers.\n\n");
249 void get_multiport(char *device, int fd)
251 struct serial_multiport_struct multi;
253 if (ioctl(fd, TIOCSERGETMULTI, &multi) < 0) {
254 perror("Cannot get multiport config");
257 printf("Multiport config for irq %d:\n", multi.irq);
258 printf("\tPort monitor = 0x%x\n", multi.port_monitor);
259 printf("\tPort1 = 0x%x, mask=0x%x, match=0x%x\n", multi.port1,
260 multi.mask1, multi.match1);
261 printf("\tPort2 = 0x%x, mask=0x%x, match=0x%x\n", multi.port2,
262 multi.mask2, multi.match2);
263 printf("\tPort3 = 0x%x, mask=0x%x, match=0x%x\n", multi.port3,
264 multi.mask3, multi.match3);
265 printf("\tPort4 = 0x%x, mask=0x%x, match=0x%x\n", multi.port4,
266 multi.mask4, multi.match4);
269 void set_multiport(char *device, int fd, char ***in_arg)
271 char **arg = *in_arg;
272 char *word, *argument;
273 struct serial_multiport_struct multi;
275 if (ioctl(fd, TIOCSERGETMULTI, &multi) < 0) {
276 perror("Cannot get multiport config");
290 if (strcasecmp(word, "port_monitor") == 0) {
291 multi.port_monitor = atonum(argument);
294 if (strcasecmp(word, "port1") == 0) {
295 multi.port1 = atonum(argument);
298 if (strcasecmp(word, "mask1") == 0) {
299 multi.mask1 = atonum(argument);
302 if (strcasecmp(word, "match1") == 0) {
303 multi.match1 = atonum(argument);
306 if (strcasecmp(word, "port2") == 0) {
307 multi.port2 = atonum(argument);
310 if (strcasecmp(word, "mask2") == 0) {
311 multi.mask2 = atonum(argument);
314 if (strcasecmp(word, "match2") == 0) {
315 multi.match2 = atonum(argument);
318 if (strcasecmp(word, "port3") == 0) {
319 multi.port3 = atonum(argument);
322 if (strcasecmp(word, "mask3") == 0) {
323 multi.mask3 = atonum(argument);
326 if (strcasecmp(word, "match3") == 0) {
327 multi.match3 = atonum(argument);
330 if (strcasecmp(word, "port4") == 0) {
331 multi.port4 = atonum(argument);
334 if (strcasecmp(word, "mask4") == 0) {
335 multi.mask4 = atonum(argument);
338 if (strcasecmp(word, "match4") == 0) {
339 multi.match4 = atonum(argument);
342 fprintf(stderr, "Unknown keyword %s.\n", word);
346 if (ioctl(fd, TIOCSERSETMULTI, &multi) < 0) {
347 perror("Cannot set multiport config");
353 void get_multiport(char *device, int fd)
355 printf("Setserial was compiled under a kernel which did not\n");
356 printf("support the special serial multiport configs.\n");
358 void set_multiport(char *device, int fd, char ***in_arg)
360 printf("Setserial was compiled under a kernel which did not\n");
361 printf("support the special serial multiport configs.\n");
366 void print_hayesesp(int fd)
368 struct hayes_esp_config esp;
370 if (ioctl(fd, TIOCGHAYESESP, &esp) < 0)
373 printf("\tHayes ESP enhanced mode configuration:\n");
374 printf("\t\tRX trigger level: %d, TX trigger level: %d\n",
375 (int)esp.rx_trigger, (int)esp.tx_trigger);
376 printf("\t\tFlow off level: %d, Flow on level: %d\n",
377 (int)esp.flow_off, (int)esp.flow_on);
378 printf("\t\tRX timeout: %u, DMA channel: %d\n\n",
379 (unsigned int)esp.rx_timeout, (int)esp.dma_channel);
382 void set_hayesesp(int fd, int cmd, int arg)
384 struct hayes_esp_config esp;
386 if (ioctl(fd, TIOCGHAYESESP, &esp) < 0) {
387 printf("\nError: rx_trigger, tx_trigger, flow_off, "
388 "flow_on, rx_timeout, and dma_channel\n"
389 "are only valid for Hayes ESP ports.\n\n");
395 esp.rx_trigger = arg;
398 esp.tx_trigger = arg;
407 esp.rx_timeout = arg;
410 esp.dma_channel = arg;
414 if (ioctl(fd, TIOCSHAYESESP, &esp) < 0) {
415 printf("Cannot set Hayes ESP info\n");
421 void get_serial(char *device)
423 struct serial_struct serinfo;
427 if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
431 serinfo.reserved_char[0] = 0;
432 if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) {
433 perror("Cannot get serial info");
437 if (serinfo.irq == 9)
438 serinfo.irq = 2; /* People understand 2 better than 9 */
440 printf("%s uart %s port 0x%.4x irq %d baud_base %d", device,
441 serial_type(serinfo.type), serinfo.port,
442 serinfo.irq, serinfo.baud_base);
443 print_flags(&serinfo, ", Flags: ", "");
445 } else if (verbosity==2) {
446 printf("%s, Line %d, UART: %s, Port: 0x%.4x, IRQ: %d\n",
447 device, serinfo.line, serial_type(serinfo.type),
448 serinfo.port, serinfo.irq);
449 printf("\tBaud_base: %d, close_delay: %d, divisor: %d\n",
450 serinfo.baud_base, serinfo.close_delay,
451 serinfo.custom_divisor);
452 if (serinfo.closing_wait == ASYNC_CLOSING_WAIT_INF)
453 strcpy(buf1, "infinte");
454 else if (serinfo.closing_wait == ASYNC_CLOSING_WAIT_NONE)
455 strcpy(buf1, "none");
457 sprintf(buf1, "%d", serinfo.closing_wait);
458 printf("\tclosing_wait: %s\n", buf1);
459 print_flags(&serinfo, "\tFlags: ", "");
465 } else if (verbosity==0) {
467 printf("%s at 0x%.4x (irq = %d) is a %s",
468 device, serinfo.port, serinfo.irq,
469 serial_type(serinfo.type));
470 print_flags(&serinfo, " (", ")");
474 printf("%s, UART: %s, Port: 0x%.4x, IRQ: %d",
475 device, serial_type(serinfo.type),
476 serinfo.port, serinfo.irq);
477 print_flags(&serinfo, ", Flags: ", "");
483 void set_serial(char *device, char ** arg)
485 struct serial_struct old_serinfo, new_serinfo;
486 struct flag_type_table *p;
492 if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
493 if (verbosity==0 && errno==ENOENT)
498 if (ioctl(fd, TIOCGSERIAL, &old_serinfo) < 0) {
499 perror("Cannot get serial info");
502 new_serinfo = old_serinfo;
504 new_serinfo.flags = 0;
512 for (p = flag_type_tbl; p->name; p++) {
513 if (!strcasecmp(p->name, word))
517 fprintf(stderr, "Invalid flag: %s\n", word);
520 if (do_invert && !(p->flags & FLAG_CAN_INVERT)) {
521 fprintf(stderr, "This flag can not be inverted: %s\n", word);
524 if ((p->flags & FLAG_NEED_ARG) && !*arg) {
525 fprintf(stderr, "Missing argument for %s\n", word);
530 new_serinfo.flags &= ~p->mask;
532 new_serinfo.flags |= p->bits;
535 new_serinfo.port = atonum(*arg++);
538 new_serinfo.irq = atonum(*arg++);
541 new_serinfo.custom_divisor = atonum(*arg++);
544 new_serinfo.type = uart_type(*arg++);
545 if (new_serinfo.type < 0) {
546 fprintf(stderr, "Illegal UART type: %s", *--arg);
551 new_serinfo.baud_base = atonum(*arg++);
554 new_serinfo.close_delay = atonum(*arg++);
557 if (!strcasecmp(*arg, "infinite"))
558 new_serinfo.closing_wait = ASYNC_CLOSING_WAIT_INF;
559 else if (!strcasecmp(*arg, "none"))
560 new_serinfo.closing_wait = ASYNC_CLOSING_WAIT_NONE;
562 new_serinfo.closing_wait = atonum(*arg);
566 if (!strcasecmp(*arg, "infinite"))
567 new_serinfo.closing_wait2 = ASYNC_CLOSING_WAIT_INF;
568 else if (!strcasecmp(*arg, "none"))
569 new_serinfo.closing_wait2 = ASYNC_CLOSING_WAIT_NONE;
571 new_serinfo.closing_wait2 = atonum(*arg);
575 if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
576 perror("Cannot set serial info");
579 if (ioctl(fd, TIOCSERCONFIG) < 0) {
580 perror("Cannot autoconfigure port");
583 if (ioctl(fd, TIOCGSERIAL, &new_serinfo) < 0) {
584 perror("Cannot get serial info");
589 if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
590 perror("Cannot set serial info");
593 get_multiport(device, fd);
596 if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
597 perror("Cannot set serial info");
600 set_multiport(device, fd, &arg);
609 set_hayesesp(fd, p->cmd, atonum(*arg++));
613 fprintf(stderr, "Internal error: unhandled cmd #%d\n", p->cmd);
617 if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
618 perror("Cannot set serial info");
626 void do_wild_intr(char *device)
632 if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
636 if (ioctl(fd, TIOCSERSWILD, &wild_mask) < 0) {
637 perror("Cannot scan for wild interrupts");
640 if (ioctl(fd, TIOCSERGWILD, &wild_mask) < 0) {
641 perror("Cannot get wild interrupt mask");
648 printf("Wild interrupts found: ");
649 for (i=0, mask=1; mask <= wild_mask; i++, mask <<= 1)
650 if (mask & wild_mask)
653 } else if (verbose_flag)
654 printf("No wild interrupts found.\n");
663 fprintf(stderr, "%s\n\n", version_str);
665 "usage:\t %s serial-device -abqvVWz [cmd1 [arg]] ... \n",
667 fprintf(stderr, "\t %s -g [-abGv] device1 ...\n\n", progname);
668 fprintf(stderr, "Available commands: (* = Takes an argument)\n");
669 fprintf(stderr, "\t\t(^ = can be preceded by a '^' to turn off the option)\n");
670 fprintf(stderr, "\t* port\t\tset the I/O port\n");
671 fprintf(stderr, "\t* irq\t\tset the interrupt\n");
672 fprintf(stderr, "\t* uart\t\tset UART type (none, 8250, 16450, 16550, 16550A,\n");
673 fprintf(stderr, "\t\t\t16650, 16650V2, 16750, 16850, 16950, 16954)\n");
674 fprintf(stderr, "\t* baud_base\tset base baud rate (CLOCK_FREQ / 16)\n");
675 fprintf(stderr, "\t* divisor\tset the custom divisor (see spd_custom)\n");
676 fprintf(stderr, "\t* close_delay\tset the amount of time (in 1/100 of a\n");
677 fprintf(stderr, "\t\t\t\tsecond) that DTR should be kept low\n");
678 fprintf(stderr, "\t\t\t\twhile being closed\n");
679 fprintf(stderr, "\t* closing_wait\tset the amount of time (in 1/100 of a\n");
680 fprintf(stderr, "\t\t\t\tsecond) that the serial port should wait for\n");
681 fprintf(stderr, "\t\t\t\tdata to be drained while being closed.\n");
682 fprintf(stderr, "\t^ fourport\tconfigure the port as an AST Fourport\n");
683 fprintf(stderr, "\t autoconfig\tautomatically configure the serial port\n");
684 fprintf(stderr, "\t^ auto_irq\ttry to determine irq during autoconfiguration\n");
685 fprintf(stderr, "\t^ skip_test\tskip UART test during autoconfiguration\n");
686 fprintf(stderr, "\n");
687 fprintf(stderr, "\t^ sak\t\tset the break key as the Secure Attention Key\n");
688 fprintf(stderr, "\t^ session_lockout Lock out callout port across different sessions\n");
689 fprintf(stderr, "\t^ pgrp_lockout\tLock out callout port across different process groups\n");
690 fprintf(stderr, "\t^ callout_nohup\tDon't hangup the tty when carrier detect drops\n");
691 fprintf(stderr, "\t\t\t\t on the callout device\n");
692 fprintf(stderr, "\t^ split_termios Use separate termios for callout and dailin lines\n");
693 fprintf(stderr, "\t^ hup_notify\tNotify a process blocked on opening a dial in line\n");
694 fprintf(stderr, "\t\t\t\twhen a process has finished using a callout\n");
695 fprintf(stderr, "\t\t\t\tline by returning EAGAIN to the open.\n");
696 fprintf(stderr, "\t^ low_latency\tMinimize receive latency at the cost of greater\n");
697 fprintf(stderr, "\t\t\t\tCPU utilization.\n");
698 fprintf(stderr, "\t get_multiport\tDisplay the multiport configuration\n");
699 fprintf(stderr, "\t set_multiport\tSet the multiport configuration\n");
700 fprintf(stderr, "\n");
702 fprintf(stderr, "\t* rx_trigger\tSet RX trigger level (ESP-only)\n");
703 fprintf(stderr, "\t* tx_trigger\tSet TX trigger level (ESP-only)\n");
704 fprintf(stderr, "\t* flow_off\tSet hardware flow off level (ESP-only)\n");
705 fprintf(stderr, "\t* flow_on\tSet hardware flow on level (ESP-only)\n");
706 fprintf(stderr, "\t* rx_timeout\tSet receive timeout (ESP-only)\n");
707 fprintf(stderr, "\t* dma_channel\tSet DMA channel (ESP-only)\n");
709 fprintf(stderr, "\n");
710 fprintf(stderr, "\t spd_hi\tuse 56kb instead of 38.4kb\n");
711 fprintf(stderr, "\t spd_vhi\tuse 115kb instead of 38.4kb\n");
712 fprintf(stderr, "\t spd_shi\tuse 230kb instead of 38.4kb\n");
713 fprintf(stderr, "\t spd_warp\tuse 460kb instead of 38.4kb\n");
714 fprintf(stderr, "\t spd_cust\tuse the custom divisor to set the speed at 38.4kb\n");
715 fprintf(stderr, "\t\t\t\t(baud rate = baud_base / custom_divisor)\n");
716 fprintf(stderr, "\t spd_normal\tuse 38.4kb when a buad rate of 38.4kb is selected\n");
717 fprintf(stderr, "\n");
718 fprintf(stderr, "Use a leading '0x' for hex numbers.\n");
719 fprintf(stderr, "CAUTION: Using an invalid port can lock up your machine!\n");
723 main(int argc, char **argv)
725 int get_flag = 0, wild_intr_flag = 0;
733 while ((c = getopt(argc, argv, "abgGqvVWz")) != EOF) {
754 fprintf(stderr, "%s\n", version_str);
774 if (wild_intr_flag) {
775 do_wild_intr(argv[optind]);
778 if (argc-optind == 1)
779 get_serial(argv[optind]);
781 set_serial(argv[optind], argv+optind+1);