]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/setserial.c
Imported from util-linux-2.5 tarball.
[thirdparty/util-linux.git] / sys-utils / setserial.c
CommitLineData
6dbe3af9
KZ
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 */
4/*
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
9 *
10 * Last modified: [tytso:19940520.0036EDT]
11 */
12
13#include <stdio.h>
14#include <fcntl.h>
15#include <termios.h>
16#include <string.h>
17#include <errno.h>
18
19#include <linux/fs.h>
20#include <linux/serial.h>
21#include <linux/tty.h>
22
23#define VERSION_STR "2.10"
24
25char *progname;
26
27int verbosity = 1; /* 1 = normal, 0=boot-time, 2=everything */
28int verbose_flag = 0; /* print results after setting a port */
29int quiet_flag = 0;
30
31struct serial_type_struct {
32 int id;
33 char *name;
34} serial_type_tbl[] = {
35 PORT_UNKNOWN, "unknown",
36 PORT_8250, "8250",
37 PORT_16450, "16450",
38 PORT_16550, "16550",
39 PORT_16550A, "16550A",
40 PORT_UNKNOWN, "none",
41 -1, NULL
42};
43
44#define CMD_FLAG 1
45#define CMD_PORT 2
46#define CMD_IRQ 3
47#define CMD_DIVISOR 4
48#define CMD_TYPE 5
49#define CMD_BASE 6
50#define CMD_DELAY 7
51#define CMD_CONFIG 8
52
53#define FLAG_CAN_INVERT 0x0001
54#define FLAG_NEED_ARG 0x0002
55
56struct flag_type_table {
57 int cmd;
58 char *name;
59 int bits;
60 int mask;
61 int level;
62 int flags;
63} flag_type_tbl[] = {
64 CMD_FLAG, "spd_normal", 0, ASYNC_SPD_MASK, 2, 0,
65 CMD_FLAG, "spd_hi", ASYNC_SPD_HI, ASYNC_SPD_MASK, 0, 0,
66 CMD_FLAG, "spd_vhi", ASYNC_SPD_VHI, ASYNC_SPD_MASK, 0, 0,
67 CMD_FLAG, "spd_cust", ASYNC_SPD_CUST, ASYNC_SPD_MASK, 0, 0,
68
69 CMD_FLAG, "SAK", ASYNC_SAK, ASYNC_SAK, 0, FLAG_CAN_INVERT,
70 CMD_FLAG, "Fourport", ASYNC_FOURPORT, ASYNC_FOURPORT, 0, FLAG_CAN_INVERT,
71 CMD_FLAG, "hup_notify", ASYNC_HUP_NOTIFY, ASYNC_HUP_NOTIFY, 0, FLAG_CAN_INVERT,
72 CMD_FLAG, "skip_test", ASYNC_SKIP_TEST,ASYNC_SKIP_TEST,2, FLAG_CAN_INVERT,
73 CMD_FLAG, "auto_irq", ASYNC_AUTO_IRQ, ASYNC_AUTO_IRQ, 2, FLAG_CAN_INVERT,
74#ifdef ASYNC_SPLIT_TERMIOS
75 CMD_FLAG, "split_termios", ASYNC_SPLIT_TERMIOS, ASYNC_SPLIT_TERMIOS, 2, FLAG_CAN_INVERT,
76#endif
77 CMD_FLAG, "session_lockout", ASYNC_SESSION_LOCKOUT, ASYNC_SESSION_LOCKOUT, 2, FLAG_CAN_INVERT,
78 CMD_FLAG, "pgrp_lockout", ASYNC_PGRP_LOCKOUT, ASYNC_PGRP_LOCKOUT, 2, FLAG_CAN_INVERT,
79#ifdef ASYNC_CALLOUT_NOHUP
80 CMD_FLAG, "callout_nohup", ASYNC_CALLOUT_NOHUP, ASYNC_CALLOUT_NOHUP, 2, FLAG_CAN_INVERT,
81#endif
82
83 CMD_PORT, "port", 0, 0, 0, FLAG_NEED_ARG,
84 CMD_IRQ, "irq", 0, 0, 0, FLAG_NEED_ARG,
85 CMD_DIVISOR, "divisor", 0, 0, 0, FLAG_NEED_ARG,
86 CMD_TYPE, "uart", 0, 0, 0, FLAG_NEED_ARG,
87 CMD_BASE, "base", 0, 0, 0, FLAG_NEED_ARG,
88 CMD_BASE, "baud_base", 0, 0, 0, FLAG_NEED_ARG,
89 CMD_DELAY, "close_delay", 0, 0, 0, FLAG_NEED_ARG,
90 CMD_CONFIG, "autoconfig", 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0,
92};
93
94char *serial_type(int id)
95{
96 int i;
97
98 for (i = 0; serial_type_tbl[i].id != -1; i++)
99 if (id == serial_type_tbl[i].id)
100 return serial_type_tbl[i].name;
101 return "undefined";
102}
103
104int uart_type(char *name)
105{
106 int i;
107
108 for (i = 0; serial_type_tbl[i].id != -1; i++)
109 if (!strcasecmp(name, serial_type_tbl[i].name))
110 return serial_type_tbl[i].id;
111 return -1;
112}
113
114
115int atonum(char *s)
116{
117 int n;
118
119 while (*s == ' ')
120 s++;
121 if (strncmp(s, "0x", 2) == 0 || strncmp(s, "0X", 2) == 0)
122 sscanf(s + 2, "%x", &n);
123 else if (s[0] == '0' && s[1])
124 sscanf(s + 1, "%o", &n);
125 else
126 sscanf(s, "%d", &n);
127 return n;
128}
129
130void print_flags(struct serial_struct *serinfo,
131 char *prefix, char *postfix)
132{
133 struct flag_type_table *p;
134 int flags;
135 int first = 1;
136
137 flags = serinfo->flags;
138
139 for (p = flag_type_tbl; p->name; p++) {
140 if (p->cmd != CMD_FLAG)
141 continue;
142 if (verbosity < p->level)
143 continue;
144 if ((flags & p->mask) == p->bits) {
145 if (first) {
146 printf("%s", prefix);
147 first = 0;
148 } else
149 printf(" ");
150 printf("%s", p->name);
151 }
152 }
153
154 if (!first)
155 printf("%s", postfix);
156}
157
158void get_serial(char *device)
159{
160 struct serial_struct serinfo;
161 int fd;
162
163 if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
164 perror(device);
165 return;
166 }
167 if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) {
168 perror("Cannot get serial info");
169 close(fd);
170 return;
171 }
172 if (serinfo.irq == 9)
173 serinfo.irq = 2; /* People understand 2 better than 9 */
174 if (verbosity==2) {
175 printf("%s, Line %d, UART: %s, Port: 0x%.4x, IRQ: %d\n",
176 device, serinfo.line, serial_type(serinfo.type),
177 serinfo.port, serinfo.irq);
178 printf("\tBaud_base: %d, close_delay: %d, divisor: %d\n",
179 serinfo.baud_base, serinfo.close_delay,
180 serinfo.custom_divisor);
181 print_flags(&serinfo, "\tFlags: ", "");
182 printf("\n\n");
183 } else if (verbosity==0) {
184 if (serinfo.type) {
185 printf("%s at 0x%.4x (irq = %d) is a %s",
186 device, serinfo.port, serinfo.irq,
187 serial_type(serinfo.type));
188 print_flags(&serinfo, " (", ")");
189 printf("\n");
190 }
191 } else {
192 printf("%s, UART: %s, Port: 0x%.4x, IRQ: %d",
193 device, serial_type(serinfo.type),
194 serinfo.port, serinfo.irq);
195 print_flags(&serinfo, ", Flags: ", "");
196 printf("\n");
197 }
198 close(fd);
199}
200
201void set_serial(char *device, char ** arg)
202{
203 struct serial_struct old_serinfo, new_serinfo;
204 struct flag_type_table *p;
205 int fd;
206 int do_invert = 0;
207 char *word;
208
209
210 if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
211 if (verbosity==0 && errno==ENOENT)
212 exit(201);
213 perror(device);
214 exit(201);
215 }
216 if (ioctl(fd, TIOCGSERIAL, &old_serinfo) < 0) {
217 perror("Cannot get serial info");
218 exit(1);
219 }
220 new_serinfo = old_serinfo;
221 while (*arg) {
222 do_invert = 0;
223 word = *arg++;
224 if (*word == '^') {
225 do_invert++;
226 word++;
227 }
228 for (p = flag_type_tbl; p->name; p++) {
229 if (!strcasecmp(p->name, word))
230 break;
231 }
232 if (!p->name) {
233 fprintf(stderr, "Invalid flag: %s\n", word);
234 exit(1);
235 }
236 if (do_invert && !(p->flags & FLAG_CAN_INVERT)) {
237 fprintf(stderr, "This flag can not be inverted: %s\n", word);
238 exit(1);
239 }
240 if ((p->flags & FLAG_NEED_ARG) && !*arg) {
241 fprintf(stderr, "Missing argument for %s\n", word);
242 exit(1);
243 }
244 switch (p->cmd) {
245 case CMD_FLAG:
246 new_serinfo.flags &= ~p->mask;
247 if (!do_invert)
248 new_serinfo.flags |= p->bits;
249 break;
250 case CMD_PORT:
251 new_serinfo.port = atonum(*arg++);
252 break;
253 case CMD_IRQ:
254 new_serinfo.irq = atonum(*arg++);
255 break;
256 case CMD_DIVISOR:
257 new_serinfo.custom_divisor = atonum(*arg++);
258 break;
259 case CMD_TYPE:
260 new_serinfo.type = uart_type(*arg++);
261 if (new_serinfo.type < 0) {
262 fprintf(stderr, "Illegal UART type: %s", *--arg);
263 exit(1);
264 }
265 break;
266 case CMD_BASE:
267 new_serinfo.baud_base = atonum(*arg++);
268 break;
269 case CMD_DELAY:
270 new_serinfo.close_delay = atonum(*arg++);
271 break;
272 case CMD_CONFIG:
273 if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
274 perror("Cannot set serial info");
275 exit(1);
276 }
277 if (ioctl(fd, TIOCSERCONFIG) < 0) {
278 perror("Cannot autoconfigure port");
279 exit(1);
280 }
281 if (ioctl(fd, TIOCGSERIAL, &new_serinfo) < 0) {
282 perror("Cannot get serial info");
283 exit(1);
284 }
285 break;
286 default:
287 fprintf(stderr, "Internal error: unhandled cmd #%d\n", p->cmd);
288 exit(1);
289 }
290 }
291 if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
292 perror("Cannot set serial info");
293 exit(1);
294 }
295 close(fd);
296 if (verbose_flag)
297 get_serial(device);
298}
299
300void do_wild_intr(char *device)
301{
302 int fd;
303 int i, mask;
304 int wild_mask = -1;
305
306 if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
307 perror(device);
308 exit(1);
309 }
310 if (ioctl(fd, TIOCSERSWILD, &wild_mask) < 0) {
311 perror("Cannot scan for wild interrupts");
312 exit(1);
313 }
314 if (ioctl(fd, TIOCSERGWILD, &wild_mask) < 0) {
315 perror("Cannot get wild interrupt mask");
316 exit(1);
317 }
318 close(fd);
319 if (quiet_flag)
320 return;
321 if (wild_mask) {
322 printf("Wild interrupts found: ");
323 for (i=0, mask=1; mask <= wild_mask; i++, mask <<= 1)
324 if (mask & wild_mask)
325 printf(" %d", i);
326 printf("\n");
327 } else if (verbose_flag)
328 printf("No wild interrupts found.\n");
329 return;
330}
331
332
333
334
335void usage()
336{
337 fprintf(stderr, "setserial Version %s\n\n", VERSION_STR);
338 fprintf(stderr,
339 "usage: %s serial-device [cmd1 [arg]] ... \n\n", progname);
340 fprintf(stderr, "Available commands: (* = Takes an argument)\n");
341 fprintf(stderr, "\t\t(^ = can be preceded by a '^' to turn off the option)\n");
342fprintf(stderr, "\t* port\t\tset the I/O port\n");
343 fprintf(stderr, "\t* irq\t\tset the interrupt\n");
344 fprintf(stderr, "\t* uart\t\tset UART type (none, 8250, 16450, 16550, 16550A\n");
345 fprintf(stderr, "\t* baud_base\tset base baud rate (CLOCK_FREQ / 16)\n");
346 fprintf(stderr, "\t* divisor\tset the custom divisor (see spd_custom)\n");
347 fprintf(stderr, "\t* close_delay\tset the amount of time (in 1/100 of a\n");
348 fprintf(stderr, "\t\t\t\tsecond) that DTR should be kept low\n");
349 fprintf(stderr, "\t\t\t\twhile being closed\n");
350
351 fprintf(stderr, "\t^ fourport\tconfigure the port as an AST Fourport\n");
352 fprintf(stderr, "\t autoconfigure\tautomatically configure the serial port\n");
353 fprintf(stderr, "\t^ auto_irq\ttry to determine irq during autoconfiguration\n");
354 fprintf(stderr, "\t^ skip_test\tskip UART test during autoconfiguration\n");
355 fprintf(stderr, "\n");
356 fprintf(stderr, "\t^ sak\t\tset the break key as the Secure Attention Key\n");
357 fprintf(stderr, "\t^ session_lockout Lock out callout port across different sessions\n");
358 fprintf(stderr, "\t^ pgrp_lockout\tLock out callout port across different process groups\n");
359#ifdef ASYNC_CALLOUT_NOHUP
360 fprintf(stderr, "\t^ callout_nohup\tDon't hangup the tty when carrier detect drops\n");
361#endif
362 fprintf(stderr, "\t\t\t\t on the callout device\n");
363#ifdef ASYNC_SPLIT_TERMIOS
364 fprintf(stderr, "\t^ split_termios Use separate termios for callout and dailin lines\n");
365#endif
366 fprintf(stderr, "\t^ hup_notify\tNotify a process blocked on opening a dial in line\n");
367 fprintf(stderr, "\t\t\t\twhen a process has finished using a callout\n");
368 fprintf(stderr, "\t\t\t\tline by returning EAGAIN to the open.\n");
369 fprintf(stderr, "\n");
370 fprintf(stderr, "\t spd_hi\tuse 56kb instead of 38.4kb\n");
371 fprintf(stderr, "\t spd_vhi\tuse 115kb instead of 38.4kb\n");
372 fprintf(stderr, "\t spd_cust\tuse the custom divisor to set the speed at 38.4kb\n");
373 fprintf(stderr, "\t\t\t\t(baud rate = baud_base / custom_divisor)\n");
374 fprintf(stderr, "\t spd_normal\tuse 38.4kb when a buad rate of 38.4kb is selected\n");
375 fprintf(stderr, "\n");
376 fprintf(stderr, "Use a leading '0x' for hex numbers.\n");
377 fprintf(stderr, "CAUTION: Using an invalid port can lock up your machine!\n");
378 exit(1);
379}
380
381main(int argc, char **argv)
382{
383 int get_flag = 0, wild_intr_flag = 0;
384 int c;
385 extern int optind;
386 extern char *optarg;
387
388 progname = argv[0];
389 if (argc == 1)
390 usage();
391 while ((c = getopt(argc, argv, "abgqvVW")) != EOF) {
392 switch (c) {
393 case 'a':
394 verbosity = 2;
395 break;
396 case 'b':
397 verbosity = 0;
398 break;
399 case 'q':
400 quiet_flag++;
401 break;
402 case 'v':
403 verbose_flag++;
404 break;
405 case 'g':
406 get_flag++;
407 break;
408 case 'V':
409 fprintf(stderr, "setserial version %s\n", VERSION_STR);
410 exit(0);
411 case 'W':
412 wild_intr_flag++;
413 break;
414 default:
415 usage();
416 }
417 }
418 if (get_flag) {
419 argv += optind;
420 while (*argv)
421 get_serial(*argv++);
422 exit(0);
423 }
424 if (argc == optind)
425 usage();
426 if (wild_intr_flag) {
427 do_wild_intr(argv[optind]);
428 exit(0);
429 }
430 if (argc-optind == 1)
431 get_serial(argv[optind]);
432 else
433 set_serial(argv[optind], argv+optind+1);
434 exit(0);
435}
436