OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / setserial / setserial.c
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 #ifdef HAVE_ASM_IOCTLS_H
20 #include <asm/ioctls.h>
21 #endif
22 #ifdef HAVE_LINUX_HAYESESP_H
23 #include <linux/hayesesp.h>
24 #endif
25 #include <linux/serial.h>
26
27 #include "version.h"
28
29 static char version_str[] = "setserial version " SETSERIAL_VERSION ", "
30         SETSERIAL_DATE;
31
32 char *progname;
33
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 */
37 int     quiet_flag = 0;
38 int     zero_flag = 0;
39
40 struct serial_type_struct {
41         int id;
42         char *name;
43 } serial_type_tbl[] = {
44         PORT_UNKNOWN,   "unknown",
45         PORT_8250,      "8250",
46         PORT_16450,     "16450",
47         PORT_16550,     "16550",
48         PORT_16550A,    "16550A",
49         PORT_CIRRUS,    "Cirrus",
50         PORT_16650,     "16650",
51         PORT_16650V2,   "16650V2",
52         PORT_16750,     "16750",
53 #ifdef PORT_16C950
54         PORT_16C950,    "16950/954",
55         PORT_16C950,    "16950",
56         PORT_16C950,    "16954",
57 #endif
58 #ifdef PORT_16654
59         PORT_16654,     "16654",
60 #endif
61 #ifdef PORT_16850
62         PORT_16850,     "16850",
63 #endif
64         PORT_UNKNOWN,   "none",
65         -1,             NULL
66 };
67
68 #define CMD_FLAG        1
69 #define CMD_PORT        2
70 #define CMD_IRQ         3
71 #define CMD_DIVISOR     4
72 #define CMD_TYPE        5
73 #define CMD_BASE        6
74 #define CMD_DELAY       7
75 #define CMD_WAIT        8
76 #define CMD_WAIT2       9
77 #define CMD_CONFIG      10
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
86
87 #define FLAG_CAN_INVERT 0x0001
88 #define FLAG_NEED_ARG   0x0002
89
90 struct flag_type_table {
91         int     cmd;
92         char    *name;
93         int     bits;
94         int     mask;
95         int     level;
96         int     flags;
97 } flag_type_tbl[] = {
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,
104         
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,
127 #ifdef TIOCGHAYESESP
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,
134 #endif
135         0,              0,              0,              0,              0, 0,
136 };
137         
138 char *serial_type(int id)
139 {
140         int i;
141
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;
145         return "undefined";
146 }
147
148 int uart_type(char *name)
149 {
150         int i;
151
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;
155         return -1;
156 }
157
158
159 int atonum(char *s)
160 {
161         int n;
162
163         while (*s == ' ')
164                 s++;
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);
169         else
170                 sscanf(s, "%d", &n);
171         return n;
172 }
173
174 void print_flags(struct serial_struct *serinfo,
175                  char *prefix, char *postfix)
176 {
177         struct  flag_type_table *p;
178         int     flags;
179         int     first = 1;
180
181         flags = serinfo->flags;
182         
183         for (p = flag_type_tbl; p->name; p++) {
184                 if (p->cmd != CMD_FLAG)
185                         continue;
186                 if (verbosity == -1) {
187                         if ((flags & p->mask) == p->bits)
188                                 printf(" %s", p->name);
189                         continue;
190                 }
191                 if (verbosity < p->level)
192                         continue;
193                 if ((flags & p->mask) == p->bits) {
194                         if (first) {
195                                 printf("%s", prefix);
196                                 first = 0;
197                         } else
198                                 printf(" ");
199                         printf("%s", p->name);
200                 }
201         }
202         
203         if (!first)
204                 printf("%s", postfix);
205 }
206
207 #ifdef TIOCSERGETMULTI
208 void print_multiport(char *device, int fd)
209 {
210         struct serial_multiport_struct multi;
211
212         if (ioctl(fd, TIOCSERGETMULTI, &multi) < 0)
213                 return;
214
215         if (!multi.port1 && !multi.port2 &&
216             !multi.port3 && !multi.port4 && !multi.port_monitor)
217                 return;
218         
219         printf("%s", device);
220         if (multi.port_monitor)
221                 printf(" port_monitor 0x%x", multi.port_monitor);
222         if (multi.port1)
223                 printf(" port1 0x%x mask1 0x%x match1 0x%x", multi.port1,
224                        multi.mask1, multi.match1);
225         if (multi.port2)
226                 printf(" port2 0x%x mask2 0x%x match2 0x%x", multi.port2,
227                        multi.mask2, multi.match2);
228         if (multi.port3)
229                 printf(" port3 0x%x mask3 0x%x match3 0x%x", multi.port3,
230                        multi.mask3, multi.match3);
231         if (multi.port4)
232                 printf(" port4 0x%x mask4 0x%x match4 0x%x", multi.port4,
233                        multi.mask4, multi.match4);
234         printf("\n");
235 }
236
237
238 void multiport_usage()
239 {
240
241         fprintf(stderr, "\nValid keywords after set_multiport are:\n");
242         fprintf(stderr, "\tport_monitor, port[1-4], mask[1-4], "
243                 "match[1-4]\n\n");
244         fprintf(stderr, "All arguments take an numeric argument following "
245                 "the keyword.\n");
246         fprintf(stderr, "Use a leading '0x' for hex numbers.\n\n");
247 }
248
249 void get_multiport(char *device, int fd)
250 {
251         struct serial_multiport_struct multi;
252
253         if (ioctl(fd, TIOCSERGETMULTI, &multi) < 0) {
254                 perror("Cannot get multiport config");
255                 exit(1);
256         }
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);
267 }
268
269 void set_multiport(char *device, int fd, char ***in_arg)
270 {
271         char **arg = *in_arg;
272         char *word, *argument;
273         struct serial_multiport_struct multi;
274
275         if (ioctl(fd, TIOCSERGETMULTI, &multi) < 0) {
276                 perror("Cannot get multiport config");
277                 exit(1);
278         }
279         if (*arg == 0) {
280                 multiport_usage();
281                 return;
282         }
283         while (*arg) {
284                 word = *arg++;
285                 if (*arg == 0) {
286                         multiport_usage();
287                         exit(1);
288                 }
289                 argument = *arg++;
290                 if (strcasecmp(word, "port_monitor") == 0) {
291                         multi.port_monitor = atonum(argument);
292                         continue;
293                 }
294                 if (strcasecmp(word, "port1") == 0) {
295                         multi.port1 = atonum(argument);
296                         continue;
297                 }
298                 if (strcasecmp(word, "mask1") == 0) {
299                         multi.mask1 = atonum(argument);
300                         continue;
301                 }
302                 if (strcasecmp(word, "match1") == 0) {
303                         multi.match1 = atonum(argument);
304                         continue;
305                 }
306                 if (strcasecmp(word, "port2") == 0) {
307                         multi.port2 = atonum(argument);
308                         continue;
309                 }
310                 if (strcasecmp(word, "mask2") == 0) {
311                         multi.mask2 = atonum(argument);
312                         continue;
313                 }
314                 if (strcasecmp(word, "match2") == 0) {
315                         multi.match2 = atonum(argument);
316                         continue;
317                 }
318                 if (strcasecmp(word, "port3") == 0) {
319                         multi.port3 = atonum(argument);
320                         continue;
321                 }
322                 if (strcasecmp(word, "mask3") == 0) {
323                         multi.mask3 = atonum(argument);
324                         continue;
325                 }
326                 if (strcasecmp(word, "match3") == 0) {
327                         multi.match3 = atonum(argument);
328                         continue;
329                 }
330                 if (strcasecmp(word, "port4") == 0) {
331                         multi.port4 = atonum(argument);
332                         continue;
333                 }
334                 if (strcasecmp(word, "mask4") == 0) {
335                         multi.mask4 = atonum(argument);
336                         continue;
337                 }
338                 if (strcasecmp(word, "match4") == 0) {
339                         multi.match4 = atonum(argument);
340                         continue;
341                 }
342                 fprintf(stderr, "Unknown keyword %s.\n", word);
343                 multiport_usage();
344                 exit(1);
345         }
346         if (ioctl(fd, TIOCSERSETMULTI, &multi) < 0) {
347                 perror("Cannot set multiport config");
348                 exit(1);
349         }
350         *in_arg = arg;
351 }
352 #else
353 void get_multiport(char *device, int fd)
354 {
355         printf("Setserial was compiled under a kernel which did not\n");
356         printf("support the special serial multiport configs.\n");
357 }
358 void set_multiport(char *device, int fd, char ***in_arg)
359 {
360         printf("Setserial was compiled under a kernel which did not\n");
361         printf("support the special serial multiport configs.\n");
362 }
363 #endif
364
365 #ifdef TIOCGHAYESESP
366 void print_hayesesp(int fd)
367 {
368         struct hayes_esp_config esp;
369
370         if (ioctl(fd, TIOCGHAYESESP, &esp) < 0)
371                 return;
372
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);
380 }
381
382 void set_hayesesp(int fd, int cmd, int arg)
383 {
384         struct hayes_esp_config esp;
385
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");
390                 exit(1);
391         }
392
393         switch (cmd) {
394         case CMD_RX_TRIG:
395                 esp.rx_trigger = arg;
396                 break;
397         case CMD_TX_TRIG:
398                 esp.tx_trigger = arg;
399                 break;
400         case CMD_FLOW_OFF:
401                 esp.flow_off = arg;
402                 break;
403         case CMD_FLOW_ON:
404                 esp.flow_on = arg;
405                 break;
406         case CMD_RX_TMOUT:
407                 esp.rx_timeout = arg;
408                 break;
409         case CMD_DMA_CHAN:
410                 esp.dma_channel = arg;
411                 break;
412         }
413
414         if (ioctl(fd, TIOCSHAYESESP, &esp) < 0) {
415                 printf("Cannot set Hayes ESP info\n");
416                 exit(1);
417         }
418 }
419 #endif
420
421 void get_serial(char *device)
422 {
423         struct serial_struct serinfo;
424         int     fd;
425         char    buf1[40];
426
427         if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
428                 perror(device);
429                 return;
430         }
431         serinfo.reserved_char[0] = 0;
432         if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) {
433                 perror("Cannot get serial info");
434                 close(fd);
435                 return;
436         }
437         if (serinfo.irq == 9)
438                 serinfo.irq = 2;        /* People understand 2 better than 9 */
439         if (verbosity==-1) {
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: ", "");
444                 printf("\n");
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");
456                 else
457                         sprintf(buf1, "%d", serinfo.closing_wait);
458                 printf("\tclosing_wait: %s\n", buf1);
459                 print_flags(&serinfo, "\tFlags: ", "");
460                 printf("\n\n");
461
462 #ifdef TIOCGHAYESESP
463                 print_hayesesp(fd);
464 #endif
465         } else if (verbosity==0) {
466                 if (serinfo.type) {
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, " (", ")");
471                         printf("\n");
472                 }
473         } else {
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: ", "");
478                 printf("\n");
479         }
480         close(fd);
481 }
482
483 void set_serial(char *device, char ** arg)
484 {
485         struct serial_struct old_serinfo, new_serinfo;
486         struct  flag_type_table *p;
487         int     fd;
488         int     do_invert = 0;
489         char    *word;
490         
491
492         if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
493                 if (verbosity==0 && errno==ENOENT)
494                         exit(201);
495                 perror(device);
496                 exit(201);
497         }
498         if (ioctl(fd, TIOCGSERIAL, &old_serinfo) < 0) {
499                 perror("Cannot get serial info");
500                 exit(1);
501         }
502         new_serinfo = old_serinfo;
503         if (zero_flag)
504                 new_serinfo.flags = 0;
505         while (*arg) {
506                 do_invert = 0;
507                 word = *arg++;
508                 if (*word == '^') {
509                         do_invert++;
510                         word++;
511                 }
512                 for (p = flag_type_tbl; p->name; p++) {
513                         if (!strcasecmp(p->name, word))
514                                 break;
515                 }
516                 if (!p->name) {
517                         fprintf(stderr, "Invalid flag: %s\n", word);
518                         exit(1);
519                 }
520                 if (do_invert && !(p->flags & FLAG_CAN_INVERT)) {
521                         fprintf(stderr, "This flag can not be inverted: %s\n", word);
522                         exit(1);
523                 }
524                 if ((p->flags & FLAG_NEED_ARG) && !*arg) {
525                         fprintf(stderr, "Missing argument for %s\n", word);
526                         exit(1);
527                 }
528                 switch (p->cmd) {
529                 case CMD_FLAG:
530                         new_serinfo.flags &= ~p->mask;
531                         if (!do_invert)
532                                 new_serinfo.flags |= p->bits;
533                         break;
534                 case CMD_PORT:
535                         new_serinfo.port = atonum(*arg++);
536                         break;
537                 case CMD_IRQ:
538                         new_serinfo.irq = atonum(*arg++);
539                         break;
540                 case CMD_DIVISOR:
541                         new_serinfo.custom_divisor = atonum(*arg++);
542                         break;
543                 case CMD_TYPE:
544                         new_serinfo.type = uart_type(*arg++);
545                         if (new_serinfo.type < 0) {
546                                 fprintf(stderr, "Illegal UART type: %s", *--arg);
547                                 exit(1);
548                         }
549                         break;
550                 case CMD_BASE:
551                         new_serinfo.baud_base = atonum(*arg++);
552                         break;
553                 case CMD_DELAY:
554                         new_serinfo.close_delay = atonum(*arg++);
555                         break;
556                 case CMD_WAIT:
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;
561                         else
562                                 new_serinfo.closing_wait = atonum(*arg);
563                         arg++;
564                         break;
565                 case CMD_WAIT2:
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;
570                         else
571                                 new_serinfo.closing_wait2 = atonum(*arg);
572                         arg++;
573                         break;
574                 case CMD_CONFIG:
575                         if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
576                                 perror("Cannot set serial info");
577                                 exit(1);
578                         }
579                         if (ioctl(fd, TIOCSERCONFIG) < 0) {
580                                 perror("Cannot autoconfigure port");
581                                 exit(1);
582                         }
583                         if (ioctl(fd, TIOCGSERIAL, &new_serinfo) < 0) {
584                                 perror("Cannot get serial info");
585                                 exit(1);
586                         }
587                         break;
588                 case CMD_GETMULTI:
589                         if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
590                                 perror("Cannot set serial info");
591                                 exit(1);
592                         }
593                         get_multiport(device, fd);
594                         break;
595                 case CMD_SETMULTI:
596                         if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
597                                 perror("Cannot set serial info");
598                                 exit(1);
599                         }
600                         set_multiport(device, fd, &arg);
601                         break;
602 #ifdef TIOCGHAYESESP
603                 case CMD_RX_TRIG:
604                 case CMD_TX_TRIG:
605                 case CMD_FLOW_OFF:
606                 case CMD_FLOW_ON:
607                 case CMD_RX_TMOUT:
608                 case CMD_DMA_CHAN:
609                         set_hayesesp(fd, p->cmd, atonum(*arg++));
610                         break;
611 #endif
612                 default:
613                         fprintf(stderr, "Internal error: unhandled cmd #%d\n", p->cmd);
614                         exit(1);
615                 }
616         }
617         if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
618                 perror("Cannot set serial info");
619                 exit(1);
620         }
621         close(fd);
622         if (verbose_flag)
623                 get_serial(device);
624 }
625
626 void do_wild_intr(char *device)
627 {
628         int     fd;
629         int     i, mask;
630         int     wild_mask = -1;
631         
632         if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
633                 perror(device);
634                 exit(1);
635         }
636         if (ioctl(fd, TIOCSERSWILD, &wild_mask) < 0) {
637                 perror("Cannot scan for wild interrupts");
638                 exit(1);
639         }
640         if (ioctl(fd, TIOCSERGWILD, &wild_mask) < 0) {
641                 perror("Cannot get wild interrupt mask");
642                 exit(1);
643         }
644         close(fd);
645         if (quiet_flag)
646                 return;
647         if (wild_mask) {
648                 printf("Wild interrupts found: ");
649                 for (i=0, mask=1; mask <= wild_mask; i++, mask <<= 1)
650                         if (mask & wild_mask)
651                                 printf(" %d", i);
652                 printf("\n");
653         } else if (verbose_flag)
654                 printf("No wild interrupts found.\n");
655         return;
656 }
657
658
659
660
661 void usage()
662 {
663         fprintf(stderr, "%s\n\n", version_str);
664         fprintf(stderr,
665                 "usage:\t %s serial-device -abqvVWz [cmd1 [arg]] ... \n", 
666                 progname);
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");
701 #ifdef TIOCGHAYESESP
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");
708 #endif
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");
720         exit(1);
721 }
722
723 main(int argc, char **argv)
724 {
725         int     get_flag = 0, wild_intr_flag = 0;
726         int     c;
727         extern int optind;
728         extern char *optarg;
729         
730         progname = argv[0];
731         if (argc == 1)
732                 usage();
733         while ((c = getopt(argc, argv, "abgGqvVWz")) != EOF) {
734                 switch (c) {
735                 case 'a':
736                         verbosity = 2;
737                         break;
738                 case 'b':
739                         verbosity = 0;
740                         break;
741                 case 'q':
742                         quiet_flag++;
743                         break;
744                 case 'v':
745                         verbose_flag++;
746                         break;
747                 case 'g':
748                         get_flag++;
749                         break;
750                 case 'G':
751                         verbosity = -1;
752                         break;
753                 case 'V':
754                         fprintf(stderr, "%s\n", version_str);
755                         exit(0);
756                 case 'W':
757                         wild_intr_flag++;
758                         break;
759                 case 'z':
760                         zero_flag++;
761                         break;
762                 default:
763                         usage();
764                 }
765         }
766         if (get_flag) {
767                 argv += optind;
768                 while (*argv)
769                         get_serial(*argv++);
770                 exit(0);
771         }
772         if (argc == optind)
773                 usage();
774         if (wild_intr_flag) {
775                 do_wild_intr(argv[optind]);
776                 exit(0);
777         }
778         if (argc-optind == 1)
779                 get_serial(argv[optind]);
780         else
781                 set_serial(argv[optind], argv+optind+1);
782         exit(0);
783 }
784