blob: 71b2745683e53256eccf91385c002d0cb9740eaf [file] [log] [blame]
Marek Bečka2cfb5762011-05-01 03:09:14 +02001/* vi: set sw=4 ts=4: */
2/*
3 * setserial implementation for busybox
4 *
5 *
6 * Copyright (C) 2011 Marek Bečka <yuen@klacno.sk>
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */
Marek Bečka2cfb5762011-05-01 03:09:14 +020010//config:config SETSERIAL
Denys Vlasenkob097a842018-12-28 03:20:17 +010011//config: bool "setserial (6.9 kb)"
Marek Bečka2cfb5762011-05-01 03:09:14 +020012//config: default y
Denys Vlasenko8f6ce092011-07-08 08:34:28 +020013//config: select PLATFORM_LINUX
Marek Bečka2cfb5762011-05-01 03:09:14 +020014//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020015//config: Retrieve or set Linux serial port.
Marek Bečka2cfb5762011-05-01 03:09:14 +020016
Denys Vlasenko97b738d2017-08-06 18:06:46 +020017//applet:IF_SETSERIAL(APPLET_NOEXEC(setserial, setserial, BB_DIR_BIN, BB_SUID_DROP, setserial))
Marek Bečka2cfb5762011-05-01 03:09:14 +020018
19//kbuild:lib-$(CONFIG_SETSERIAL) += setserial.o
20
21#include "libbb.h"
22#include <assert.h>
23
24#ifndef PORT_UNKNOWN
25# define PORT_UNKNOWN 0
26#endif
27#ifndef PORT_8250
28# define PORT_8250 1
29#endif
30#ifndef PORT_16450
31# define PORT_16450 2
32#endif
33#ifndef PORT_16550
34# define PORT_16550 3
35#endif
36#ifndef PORT_16550A
37# define PORT_16550A 4
38#endif
39#ifndef PORT_CIRRUS
40# define PORT_CIRRUS 5
41#endif
42#ifndef PORT_16650
43# define PORT_16650 6
44#endif
45#ifndef PORT_16650V2
46# define PORT_16650V2 7
47#endif
48#ifndef PORT_16750
49# define PORT_16750 8
50#endif
51#ifndef PORT_STARTECH
52# define PORT_STARTECH 9
53#endif
54#ifndef PORT_16C950
55# define PORT_16C950 10
56#endif
57#ifndef PORT_16654
58# define PORT_16654 11
59#endif
60#ifndef PORT_16850
61# define PORT_16850 12
62#endif
63#ifndef PORT_RSA
64# define PORT_RSA 13
65#endif
66#ifndef PORT_NS16550A
67# define PORT_NS16550A 14
68#endif
69#ifndef PORT_XSCALE
70# define PORT_XSCALE 15
71#endif
72#ifndef PORT_RM9000
73# define PORT_RM9000 16
74#endif
75#ifndef PORT_OCTEON
76# define PORT_OCTEON 17
77#endif
78#ifndef PORT_AR7
79# define PORT_AR7 18
80#endif
81#ifndef PORT_U6_16550A
82# define PORT_U6_16550A 19
83#endif
84
85#ifndef ASYNCB_HUP_NOTIFY
86# define ASYNCB_HUP_NOTIFY 0
87#endif
88#ifndef ASYNCB_FOURPORT
89# define ASYNCB_FOURPORT 1
90#endif
91#ifndef ASYNCB_SAK
92# define ASYNCB_SAK 2
93#endif
94#ifndef ASYNCB_SPLIT_TERMIOS
95# define ASYNCB_SPLIT_TERMIOS 3
96#endif
97#ifndef ASYNCB_SPD_HI
98# define ASYNCB_SPD_HI 4
99#endif
100#ifndef ASYNCB_SPD_VHI
101# define ASYNCB_SPD_VHI 5
102#endif
103#ifndef ASYNCB_SKIP_TEST
104# define ASYNCB_SKIP_TEST 6
105#endif
106#ifndef ASYNCB_AUTO_IRQ
107# define ASYNCB_AUTO_IRQ 7
108#endif
109#ifndef ASYNCB_SESSION_LOCKOUT
110# define ASYNCB_SESSION_LOCKOUT 8
111#endif
112#ifndef ASYNCB_PGRP_LOCKOUT
113# define ASYNCB_PGRP_LOCKOUT 9
114#endif
115#ifndef ASYNCB_CALLOUT_NOHUP
116# define ASYNCB_CALLOUT_NOHUP 10
117#endif
118#ifndef ASYNCB_SPD_SHI
119# define ASYNCB_SPD_SHI 12
120#endif
121#ifndef ASYNCB_LOW_LATENCY
122# define ASYNCB_LOW_LATENCY 13
123#endif
124#ifndef ASYNCB_BUGGY_UART
125# define ASYNCB_BUGGY_UART 14
126#endif
127
128#ifndef ASYNC_HUP_NOTIFY
129# define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY)
130#endif
131#ifndef ASYNC_FOURPORT
132# define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT)
133#endif
134#ifndef ASYNC_SAK
135# define ASYNC_SAK (1U << ASYNCB_SAK)
136#endif
137#ifndef ASYNC_SPLIT_TERMIOS
138# define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS)
139#endif
140#ifndef ASYNC_SPD_HI
141# define ASYNC_SPD_HI (1U << ASYNCB_SPD_HI)
142#endif
143#ifndef ASYNC_SPD_VHI
144# define ASYNC_SPD_VHI (1U << ASYNCB_SPD_VHI)
145#endif
146#ifndef ASYNC_SKIP_TEST
147# define ASYNC_SKIP_TEST (1U << ASYNCB_SKIP_TEST)
148#endif
149#ifndef ASYNC_AUTO_IRQ
150# define ASYNC_AUTO_IRQ (1U << ASYNCB_AUTO_IRQ)
151#endif
152#ifndef ASYNC_SESSION_LOCKOUT
153# define ASYNC_SESSION_LOCKOUT (1U << ASYNCB_SESSION_LOCKOUT)
154#endif
155#ifndef ASYNC_PGRP_LOCKOUT
156# define ASYNC_PGRP_LOCKOUT (1U << ASYNCB_PGRP_LOCKOUT)
157#endif
158#ifndef ASYNC_CALLOUT_NOHUP
159# define ASYNC_CALLOUT_NOHUP (1U << ASYNCB_CALLOUT_NOHUP)
160#endif
161#ifndef ASYNC_SPD_SHI
162# define ASYNC_SPD_SHI (1U << ASYNCB_SPD_SHI)
163#endif
164#ifndef ASYNC_LOW_LATENCY
165# define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY)
166#endif
167#ifndef ASYNC_BUGGY_UART
168# define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART)
169#endif
170
171#ifndef ASYNC_SPD_CUST
172# define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI)
173#endif
174#ifndef ASYNC_SPD_WARP
175# define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI)
176#endif
177#ifndef ASYNC_SPD_MASK
178# define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI)
179#endif
180
181#ifndef ASYNC_CLOSING_WAIT_INF
182# define ASYNC_CLOSING_WAIT_INF 0
183#endif
184#ifndef ASYNC_CLOSING_WAIT_NONE
185# define ASYNC_CLOSING_WAIT_NONE 65535
186#endif
187
188#ifndef _LINUX_SERIAL_H
189struct serial_struct {
190 int type;
191 int line;
192 unsigned int port;
193 int irq;
194 int flags;
195 int xmit_fifo_size;
196 int custom_divisor;
197 int baud_base;
198 unsigned short close_delay;
199 char io_type;
200 char reserved_char[1];
201 int hub6;
202 unsigned short closing_wait; /* time to wait before closing */
203 unsigned short closing_wait2; /* no longer used... */
204 unsigned char *iomem_base;
205 unsigned short iomem_reg_shift;
206 unsigned int port_high;
207 unsigned long iomap_base; /* cookie passed into ioremap */
208};
209#endif
210
211//usage:#define setserial_trivial_usage
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200212//usage: "[-abGvz] { DEVICE [PARAMETER [ARG]]... | -g DEVICE... }"
Marek Bečka2cfb5762011-05-01 03:09:14 +0200213//usage:#define setserial_full_usage "\n\n"
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200214//usage: "Print or set serial port parameters"
215//usage: "\n"
216//usage: "\n"" -a Print all"
217//usage: "\n"" -b Print summary"
218//usage: "\n"" -G Print as setserial PARAMETERs"
219//usage: "\n"" -v Verbose"
220//usage: "\n"" -z Zero out serial flags before setting"
221//usage: "\n"" -g All args are device names"
222//usage: "\n"
223//usage: "\n""PARAMETERs: (* = takes ARG, ^ = can be turned off by preceding ^)"
224//usage: "\n"" *port, *irq, *divisor, *uart, *baud_base, *close_delay, *closing_wait,"
225//usage: "\n"" ^fourport, ^auto_irq, ^skip_test, ^sak, ^session_lockout, ^pgrp_lockout,"
226//usage: "\n"" ^callout_nohup, ^split_termios, ^hup_notify, ^low_latency, autoconfig,"
227//usage: "\n"" spd_normal, spd_hi, spd_vhi, spd_shi, spd_warp, spd_cust"
228//usage: "\n""ARG for uart:"
229//usage: "\n"" unknown, 8250, 16450, 16550, 16550A, Cirrus, 16650, 16650V2, 16750,"
230//usage: "\n"" 16950, 16954, 16654, 16850, RSA, NS16550A, XSCALE, RM9000, OCTEON, AR7,"
231//usage: "\n"" U6_16550A"
Marek Bečka2cfb5762011-05-01 03:09:14 +0200232
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200233// option string is "bGavzgq". "q" is accepted but ignored.
Marek Bečka2cfb5762011-05-01 03:09:14 +0200234#define OPT_PRINT_SUMMARY (1 << 0)
235#define OPT_PRINT_FEDBACK (1 << 1)
236#define OPT_PRINT_ALL (1 << 2)
237#define OPT_VERBOSE (1 << 3)
238#define OPT_ZERO (1 << 4)
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200239#define OPT_LIST_OF_DEVS (1 << 5)
240/*#define OPT_QUIET (1 << 6)*/
Marek Bečka2cfb5762011-05-01 03:09:14 +0200241
242#define OPT_MODE_MASK \
243 (OPT_PRINT_ALL | OPT_PRINT_SUMMARY | OPT_PRINT_FEDBACK)
244
245enum print_mode
246{
247 PRINT_NORMAL = 0,
248 PRINT_SUMMARY = (1 << 0),
249 PRINT_FEDBACK = (1 << 1),
250 PRINT_ALL = (1 << 2),
251};
252
253#define CTL_SET (1 << 0)
254#define CTL_CONFIG (1 << 1)
255#define CTL_GET (1 << 2)
256#define CTL_CLOSE (1 << 3)
257#define CTL_NODIE (1 << 4)
258
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200259static const char serial_types[] ALIGN1 =
Marek Bečka2cfb5762011-05-01 03:09:14 +0200260 "unknown\0" /* 0 */
261 "8250\0" /* 1 */
262 "16450\0" /* 2 */
263 "16550\0" /* 3 */
264 "16550A\0" /* 4 */
265 "Cirrus\0" /* 5 */
266 "16650\0" /* 6 */
267 "16650V2\0" /* 7 */
268 "16750\0" /* 8 */
269 "16950\0" /* 9 UNIMPLEMENTED: also know as "16950/954" */
270 "16954\0" /* 10 */
271 "16654\0" /* 11 */
272 "16850\0" /* 12 */
273 "RSA\0" /* 13 */
274#ifndef SETSERIAL_BASE
275 "NS16550A\0" /* 14 */
276 "XSCALE\0" /* 15 */
277 "RM9000\0" /* 16 */
278 "OCTEON\0" /* 17 */
279 "AR7\0" /* 18 */
280 "U6_16550A\0" /* 19 */
281#endif
282;
283
284#ifndef SETSERIAL_BASE
285# define MAX_SERIAL_TYPE 19
286#else
287# define MAX_SERIAL_TYPE 13
288#endif
289
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200290static const char commands[] ALIGN1 =
Marek Bečka2cfb5762011-05-01 03:09:14 +0200291 "spd_normal\0"
292 "spd_hi\0"
293 "spd_vhi\0"
294 "spd_shi\0"
295 "spd_warp\0"
296 "spd_cust\0"
297
298 "sak\0"
299 "fourport\0"
300 "hup_notify\0"
301 "skip_test\0"
302 "auto_irq\0"
303 "split_termios\0"
304 "session_lockout\0"
305 "pgrp_lockout\0"
306 "callout_nohup\0"
307 "low_latency\0"
308
309 "port\0"
310 "irq\0"
311 "divisor\0"
312 "uart\0"
Bernhard Reutner-Fischerc6087312013-03-22 17:04:51 +0100313 "baud_base\0"
Marek Bečka2cfb5762011-05-01 03:09:14 +0200314 "close_delay\0"
315 "closing_wait\0"
316
317 "autoconfig\0"
318;
319
320enum
321{
322 CMD_SPD_NORMAL = 0,
323 CMD_SPD_HI,
324 CMD_SPD_VHI,
325 CMD_SPD_SHI,
326 CMD_SPD_WARP,
327 CMD_SPD_CUST,
328
329 CMD_FLAG_SAK,
330 CMD_FLAG_FOURPORT,
331 CMD_FLAG_NUP_NOTIFY,
332 CMD_FLAG_SKIP_TEST,
333 CMD_FLAG_AUTO_IRQ,
334 CMD_FLAG_SPLIT_TERMIOS,
335 CMD_FLAG_SESSION_LOCKOUT,
336 CMD_FLAG_PGRP_LOCKOUT,
337 CMD_FLAG_CALLOUT_NOHUP,
338 CMD_FLAG_LOW_LATENCY,
339
340 CMD_PORT,
341 CMD_IRQ,
342 CMD_DIVISOR,
343 CMD_UART,
344 CMD_BASE,
345 CMD_DELAY,
346 CMD_WAIT,
347
348 CMD_AUTOCONFIG,
349
350 CMD_FLAG_FIRST = CMD_FLAG_SAK,
351 CMD_FLAG_LAST = CMD_FLAG_LOW_LATENCY,
352};
353
354static bool cmd_noprint(int cmd)
355{
356 return (cmd >= CMD_FLAG_SKIP_TEST && cmd <= CMD_FLAG_CALLOUT_NOHUP);
357}
358
359static bool cmd_is_flag(int cmd)
360{
361 return (cmd >= CMD_FLAG_FIRST && cmd <= CMD_FLAG_LAST);
362}
363
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200364static bool cmd_needs_arg(int cmd)
Marek Bečka2cfb5762011-05-01 03:09:14 +0200365{
366 return (cmd >= CMD_PORT && cmd <= CMD_WAIT);
367}
368
369#define ALL_SPD ( \
370 ASYNC_SPD_HI | ASYNC_SPD_VHI | ASYNC_SPD_SHI | \
371 ASYNC_SPD_WARP | ASYNC_SPD_CUST \
372 )
373
374#define ALL_FLAGS ( \
375 ASYNC_SAK | ASYNC_FOURPORT | ASYNC_HUP_NOTIFY | \
376 ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ | ASYNC_SPLIT_TERMIOS | \
377 ASYNC_SESSION_LOCKOUT | ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP | \
378 ASYNC_LOW_LATENCY \
379 )
380
381#if (ALL_SPD | ALL_FLAGS) > 0xffff
382# error "Unexpected flags size"
383#endif
384
385static const uint16_t setbits[CMD_FLAG_LAST + 1] =
386{
387 0,
388 ASYNC_SPD_HI,
389 ASYNC_SPD_VHI,
390 ASYNC_SPD_SHI,
391 ASYNC_SPD_WARP,
392 ASYNC_SPD_CUST,
393
394 ASYNC_SAK,
395 ASYNC_FOURPORT,
396 ASYNC_HUP_NOTIFY,
397 ASYNC_SKIP_TEST,
398 ASYNC_AUTO_IRQ,
399 ASYNC_SPLIT_TERMIOS,
400 ASYNC_SESSION_LOCKOUT,
401 ASYNC_PGRP_LOCKOUT,
402 ASYNC_CALLOUT_NOHUP,
403 ASYNC_LOW_LATENCY
404};
405
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200406#define STR_INFINITE "infinite"
407#define STR_NONE "none"
Marek Bečka2cfb5762011-05-01 03:09:14 +0200408
409static const char *uart_type(int type)
410{
411 if (type > MAX_SERIAL_TYPE)
412 return "undefined";
413
414 return nth_string(serial_types, type);
415}
416
417/* libbb candidate */
418static int index_in_strings_case_insensitive(const char *strings, const char *key)
419{
420 int idx = 0;
421
422 while (*strings) {
423 if (strcasecmp(strings, key) == 0) {
424 return idx;
425 }
426 strings += strlen(strings) + 1; /* skip NUL */
427 idx++;
428 }
429 return -1;
430}
431
432static int uart_id(const char *name)
433{
434 return index_in_strings_case_insensitive(serial_types, name);
435}
436
437static const char *get_spd(int flags, enum print_mode mode)
438{
439 int idx;
440
441 switch (flags & ASYNC_SPD_MASK) {
442 case ASYNC_SPD_HI:
443 idx = CMD_SPD_HI;
444 break;
445 case ASYNC_SPD_VHI:
446 idx = CMD_SPD_VHI;
447 break;
448 case ASYNC_SPD_SHI:
449 idx = CMD_SPD_SHI;
450 break;
451 case ASYNC_SPD_WARP:
452 idx = CMD_SPD_WARP;
453 break;
454 case ASYNC_SPD_CUST:
455 idx = CMD_SPD_CUST;
456 break;
457 default:
458 if (mode < PRINT_FEDBACK)
459 return NULL;
460 idx = CMD_SPD_NORMAL;
461 }
462
463 return nth_string(commands, idx);
464}
465
466static int get_numeric(const char *arg)
467{
468 return bb_strtol(arg, NULL, 0);
469}
470
471static int get_wait(const char *arg)
472{
473 if (strcasecmp(arg, STR_NONE) == 0)
474 return ASYNC_CLOSING_WAIT_NONE;
475
476 if (strcasecmp(arg, STR_INFINITE) == 0)
477 return ASYNC_CLOSING_WAIT_INF;
478
479 return get_numeric(arg);
480}
481
482static int get_uart(const char *arg)
483{
484 int uart = uart_id(arg);
485
486 if (uart < 0)
487 bb_error_msg_and_die("illegal UART type: %s", arg);
488
489 return uart;
490}
491
492static int serial_open(const char *dev, bool quiet)
493{
494 int fd;
495
496 fd = device_open(dev, O_RDWR | O_NONBLOCK);
497 if (fd < 0 && !quiet)
498 bb_simple_perror_msg(dev);
499
500 return fd;
501}
502
503static int serial_ctl(int fd, int ops, struct serial_struct *serinfo)
504{
505 int ret = 0;
506 const char *err;
507
508 if (ops & CTL_SET) {
509 ret = ioctl(fd, TIOCSSERIAL, serinfo);
510 if (ret < 0) {
511 err = "can't set serial info";
512 goto fail;
513 }
514 }
515
516 if (ops & CTL_CONFIG) {
517 ret = ioctl(fd, TIOCSERCONFIG);
518 if (ret < 0) {
519 err = "can't autoconfigure port";
520 goto fail;
521 }
522 }
523
524 if (ops & CTL_GET) {
525 ret = ioctl(fd, TIOCGSERIAL, serinfo);
526 if (ret < 0) {
527 err = "can't get serial info";
528 goto fail;
529 }
530 }
531 nodie:
532 if (ops & CTL_CLOSE)
533 close(fd);
534
535 return ret;
536 fail:
537 bb_simple_perror_msg(err);
538 if (ops & CTL_NODIE)
539 goto nodie;
540 exit(EXIT_FAILURE);
541}
542
543static void print_flag(const char **prefix, const char *flag)
544{
545 printf("%s%s", *prefix, flag);
546 *prefix = " ";
547}
548
549static void print_serial_flags(int serial_flags, enum print_mode mode,
550 const char *prefix, const char *postfix)
551{
552 int i;
553 const char *spd, *pr;
554
555 pr = prefix;
556
557 spd = get_spd(serial_flags, mode);
558 if (spd)
559 print_flag(&pr, spd);
560
561 for (i = CMD_FLAG_FIRST; i <= CMD_FLAG_LAST; i++) {
562 if ((serial_flags & setbits[i])
563 && (mode > PRINT_SUMMARY || !cmd_noprint(i))
564 ) {
565 print_flag(&pr, nth_string(commands, i));
566 }
567 }
568
569 puts(pr == prefix ? "" : postfix);
570}
571
572static void print_closing_wait(unsigned int closing_wait)
573{
574 switch (closing_wait) {
575 case ASYNC_CLOSING_WAIT_NONE:
576 puts(STR_NONE);
577 break;
578 case ASYNC_CLOSING_WAIT_INF:
579 puts(STR_INFINITE);
580 break;
581 default:
582 printf("%u\n", closing_wait);
583 }
584}
585
586static void serial_get(const char *device, enum print_mode mode)
587{
588 int fd, ret;
589 const char *uart, *prefix, *postfix;
590 struct serial_struct serinfo;
591
592 fd = serial_open(device, /*quiet:*/ mode == PRINT_SUMMARY);
593 if (fd < 0)
594 return;
595
596 ret = serial_ctl(fd, CTL_GET | CTL_CLOSE | CTL_NODIE, &serinfo);
597 if (ret < 0)
598 return;
599
600 uart = uart_type(serinfo.type);
601 prefix = ", Flags: ";
602 postfix = "";
603
604 switch (mode) {
605 case PRINT_NORMAL:
606 printf("%s, UART: %s, Port: 0x%.4x, IRQ: %d",
607 device, uart, serinfo.port, serinfo.irq);
608 break;
609 case PRINT_SUMMARY:
610 if (!serinfo.type)
611 return;
612 printf("%s at 0x%.4x (irq = %d) is a %s",
613 device, serinfo.port, serinfo.irq, uart);
614 prefix = " (";
615 postfix = ")";
616 break;
617 case PRINT_FEDBACK:
618 printf("%s uart %s port 0x%.4x irq %d baud_base %d", device,
619 uart, serinfo.port, serinfo.irq, serinfo.baud_base);
620 prefix = " ";
621 break;
622 case PRINT_ALL:
623 printf("%s, Line %d, UART: %s, Port: 0x%.4x, IRQ: %d\n",
624 device, serinfo.line, uart, serinfo.port, serinfo.irq);
625 printf("\tBaud_base: %d, close_delay: %u, divisor: %d\n",
626 serinfo.baud_base, serinfo.close_delay,
627 serinfo.custom_divisor);
628 printf("\tclosing_wait: ");
629 print_closing_wait(serinfo.closing_wait);
630 prefix = "\tFlags: ";
631 postfix = "\n";
632 break;
633 default:
634 assert(0);
635 }
636
637 print_serial_flags(serinfo.flags, mode, prefix, postfix);
638}
639
640static int find_cmd(const char *cmd)
641{
642 int idx;
643
644 idx = index_in_strings_case_insensitive(commands, cmd);
645 if (idx < 0)
646 bb_error_msg_and_die("invalid flag: %s", cmd);
647
648 return idx;
649}
650
651static void serial_set(char **arg, int opts)
652{
653 struct serial_struct serinfo;
Marek Bečka2cfb5762011-05-01 03:09:14 +0200654 int fd;
655
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200656 fd = serial_open(*arg, /*quiet:*/ false);
Marek Bečka2cfb5762011-05-01 03:09:14 +0200657 if (fd < 0)
658 exit(201);
659
660 serial_ctl(fd, CTL_GET, &serinfo);
661
662 if (opts & OPT_ZERO)
663 serinfo.flags = 0;
664
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200665 while (*++arg) {
666 const char *word;
Marek Bečka2cfb5762011-05-01 03:09:14 +0200667 int invert;
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200668 int cmd;
Marek Bečka2cfb5762011-05-01 03:09:14 +0200669
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200670 word = *arg;
671 invert = (word[0] == '^');
Marek Bečka2cfb5762011-05-01 03:09:14 +0200672 word += invert;
673
674 cmd = find_cmd(word);
675
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200676 if (cmd_needs_arg(cmd))
677 if (*++arg == NULL)
678 bb_error_msg_and_die(bb_msg_requires_arg, word);
Marek Bečka2cfb5762011-05-01 03:09:14 +0200679
680 if (invert && !cmd_is_flag(cmd))
681 bb_error_msg_and_die("can't invert %s", word);
682
683 switch (cmd) {
684 case CMD_SPD_NORMAL:
685 case CMD_SPD_HI:
686 case CMD_SPD_VHI:
687 case CMD_SPD_SHI:
688 case CMD_SPD_WARP:
689 case CMD_SPD_CUST:
Denys Vlasenko90ea1e32011-05-02 02:47:25 +0200690 serinfo.flags &= ~ASYNC_SPD_MASK;
Marek Bečka2cfb5762011-05-01 03:09:14 +0200691 /* fallthrough */
692 case CMD_FLAG_SAK:
693 case CMD_FLAG_FOURPORT:
694 case CMD_FLAG_NUP_NOTIFY:
695 case CMD_FLAG_SKIP_TEST:
696 case CMD_FLAG_AUTO_IRQ:
697 case CMD_FLAG_SPLIT_TERMIOS:
698 case CMD_FLAG_SESSION_LOCKOUT:
699 case CMD_FLAG_PGRP_LOCKOUT:
700 case CMD_FLAG_CALLOUT_NOHUP:
701 case CMD_FLAG_LOW_LATENCY:
702 if (invert)
703 serinfo.flags &= ~setbits[cmd];
704 else
705 serinfo.flags |= setbits[cmd];
706 break;
707 case CMD_PORT:
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200708 serinfo.port = get_numeric(*arg);
Marek Bečka2cfb5762011-05-01 03:09:14 +0200709 break;
710 case CMD_IRQ:
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200711 serinfo.irq = get_numeric(*arg);
Marek Bečka2cfb5762011-05-01 03:09:14 +0200712 break;
713 case CMD_DIVISOR:
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200714 serinfo.custom_divisor = get_numeric(*arg);
Marek Bečka2cfb5762011-05-01 03:09:14 +0200715 break;
716 case CMD_UART:
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200717 serinfo.type = get_uart(*arg);
Marek Bečka2cfb5762011-05-01 03:09:14 +0200718 break;
719 case CMD_BASE:
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200720 serinfo.baud_base = get_numeric(*arg);
Marek Bečka2cfb5762011-05-01 03:09:14 +0200721 break;
722 case CMD_DELAY:
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200723 serinfo.close_delay = get_numeric(*arg);
Marek Bečka2cfb5762011-05-01 03:09:14 +0200724 break;
725 case CMD_WAIT:
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200726 serinfo.closing_wait = get_wait(*arg);
Marek Bečka2cfb5762011-05-01 03:09:14 +0200727 break;
728 case CMD_AUTOCONFIG:
729 serial_ctl(fd, CTL_SET | CTL_CONFIG | CTL_GET, &serinfo);
730 break;
731 default:
732 assert(0);
733 }
734 }
735
736 serial_ctl(fd, CTL_SET | CTL_CLOSE, &serinfo);
737}
738
739int setserial_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
740int setserial_main(int argc UNUSED_PARAM, char **argv)
741{
742 int opts;
743
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200744 opts = getopt32(argv, "^" "bGavzgq" "\0" "-1:b-aG:G-ab:a-bG");
Marek Bečka2cfb5762011-05-01 03:09:14 +0200745 argv += optind;
746
Denys Vlasenko97b738d2017-08-06 18:06:46 +0200747 if (!argv[1]) /* one arg only? (nothing to change?) */
748 opts |= OPT_LIST_OF_DEVS; /* force display */
Marek Bečka2cfb5762011-05-01 03:09:14 +0200749
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200750 if (!(opts & OPT_LIST_OF_DEVS)) {
Marek Bečka2cfb5762011-05-01 03:09:14 +0200751 serial_set(argv, opts);
752 argv[1] = NULL;
753 }
754
Denys Vlasenko97b738d2017-08-06 18:06:46 +0200755 /* -v effect: "after setting params, do not be silent, show them" */
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200756 if (opts & (OPT_VERBOSE | OPT_LIST_OF_DEVS)) {
Marek Bečka2cfb5762011-05-01 03:09:14 +0200757 do {
Denys Vlasenko08e66a82017-08-06 17:59:37 +0200758 serial_get(*argv, opts & OPT_MODE_MASK);
759 } while (*++argv);
Marek Bečka2cfb5762011-05-01 03:09:14 +0200760 }
761
762 return EXIT_SUCCESS;
763}