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