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