diff options
author | Marek Bečka <yuen@klacno.sk> | 2011-05-01 03:09:14 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-01 14:38:31 +0200 |
commit | 2cfb57647b072900b5e66977c500c6ee0978dd0e (patch) | |
tree | 0a28ae8ca722e7159fc2064966b003a567c02241 /miscutils | |
parent | 2a6d5988b4aabc9d5cbb466ab875db20104a5056 (diff) | |
download | busybox-w32-2cfb57647b072900b5e66977c500c6ee0978dd0e.tar.gz busybox-w32-2cfb57647b072900b5e66977c500c6ee0978dd0e.tar.bz2 busybox-w32-2cfb57647b072900b5e66977c500c6ee0978dd0e.zip |
setserial: new applet
text data bss dec hex filename
873605 493 7584 881682 d7412 busybox_old
876354 493 7584 884431 d7ecf busybox_unstripped
Signed-off-by: Marek Bečka <yuen@klacno.sk>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'miscutils')
-rw-r--r-- | miscutils/setserial.c | 763 |
1 files changed, 763 insertions, 0 deletions
diff --git a/miscutils/setserial.c b/miscutils/setserial.c new file mode 100644 index 000000000..501beaacc --- /dev/null +++ b/miscutils/setserial.c | |||
@@ -0,0 +1,763 @@ | |||
1 | /* 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 | ||
12 | //config: bool "setserial" | ||
13 | //config: default y | ||
14 | //config: depends on PLATFORM_LINUX | ||
15 | //config: help | ||
16 | //config: Retrieve or set Linux serial port. | ||
17 | |||
18 | //applet:IF_SETSERIAL(APPLET(setserial, BB_DIR_BIN, BB_SUID_DROP)) | ||
19 | |||
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 | ||
190 | struct 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 | ||
213 | //usage: "[-gabGvzV] DEVICE [PARAMETER [ARG]]..." | ||
214 | //usage:#define setserial_full_usage "\n\n" | ||
215 | //usage: "Request or set Linux serial port information\n\n" | ||
216 | //usage: "Options:\n" | ||
217 | //usage: " -g Interpret parameters as list of devices for reporting" | ||
218 | //usage: " -a Print all available information\n" | ||
219 | //usage: " -b Print summary information\n" | ||
220 | //usage: " -G Print in form which can be fed back\n" | ||
221 | //usage: " to setserial as command line parameters\n" | ||
222 | //usage: " -z Zero out serial flags before setting\n" | ||
223 | //usage: " -v Verbose\n" | ||
224 | //usage: "\n" | ||
225 | //usage: "Parameters: (* = takes an argument, ^ = can be turned off by preceding ^)\n" | ||
226 | //usage: " *port, *irq, *divisor, *uart, *baund_base, *close_delay, *closing_wait,\n" | ||
227 | //usage: " ^fourport, ^auto_irq, ^skip_test, ^sak, ^session_lockout, ^pgrp_lockout,\n" | ||
228 | //usage: " ^callout_nohup, ^split_termios, ^hup_notify, ^low_latency, autoconfig,\n" | ||
229 | //usage: " spd_normal, spd_hi, spd_vhi, spd_shi, spd_warp, spd_cust\n" | ||
230 | //usage: "\n" | ||
231 | //usage: "UART types:\n" | ||
232 | //usage: " unknown, 8250, 16450, 16550, 16550A, Cirrus, 16650, 16650V2, 16750,\n" | ||
233 | //usage: " 16950, 16954, 16654, 16850, RSA, NS16550A, XSCALE, RM9000, OCTEON, AR7,\n" | ||
234 | //usage: " U6_16550A" | ||
235 | |||
236 | #define OPT_PRINT_SUMMARY (1 << 0) | ||
237 | #define OPT_PRINT_FEDBACK (1 << 1) | ||
238 | #define OPT_PRINT_ALL (1 << 2) | ||
239 | #define OPT_VERBOSE (1 << 3) | ||
240 | #define OPT_ZERO (1 << 4) | ||
241 | #define OPT_GET (1 << 5) | ||
242 | |||
243 | #define OPT_MODE_MASK \ | ||
244 | (OPT_PRINT_ALL | OPT_PRINT_SUMMARY | OPT_PRINT_FEDBACK) | ||
245 | |||
246 | enum 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 | |||
260 | static const char serial_types[] = | ||
261 | "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 | |||
291 | static const char commands[] = | ||
292 | "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" | ||
314 | "baund_base\0" | ||
315 | "close_delay\0" | ||
316 | "closing_wait\0" | ||
317 | |||
318 | "autoconfig\0" | ||
319 | ; | ||
320 | |||
321 | enum | ||
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 | |||
355 | static bool cmd_noprint(int cmd) | ||
356 | { | ||
357 | return (cmd >= CMD_FLAG_SKIP_TEST && cmd <= CMD_FLAG_CALLOUT_NOHUP); | ||
358 | } | ||
359 | |||
360 | static bool cmd_is_flag(int cmd) | ||
361 | { | ||
362 | return (cmd >= CMD_FLAG_FIRST && cmd <= CMD_FLAG_LAST); | ||
363 | } | ||
364 | |||
365 | static bool cmd_need_arg(int cmd) | ||
366 | { | ||
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 | |||
386 | static 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 | |||
407 | static const char STR_INFINITE[] = "infinite"; | ||
408 | static const char STR_NONE[] = "none"; | ||
409 | |||
410 | static 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 */ | ||
419 | static 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 | |||
433 | static int uart_id(const char *name) | ||
434 | { | ||
435 | return index_in_strings_case_insensitive(serial_types, name); | ||
436 | } | ||
437 | |||
438 | static 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 | |||
467 | static int get_numeric(const char *arg) | ||
468 | { | ||
469 | return bb_strtol(arg, NULL, 0); | ||
470 | } | ||
471 | |||
472 | static 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 | |||
483 | static 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 | |||
493 | static 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 | |||
504 | static 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 | |||
544 | static void print_flag(const char **prefix, const char *flag) | ||
545 | { | ||
546 | printf("%s%s", *prefix, flag); | ||
547 | *prefix = " "; | ||
548 | } | ||
549 | |||
550 | static 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 | |||
573 | static 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 | |||
587 | static 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 | |||
641 | static 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 | |||
652 | static void serial_set(char **arg, int opts) | ||
653 | { | ||
654 | struct serial_struct serinfo; | ||
655 | int cmd; | ||
656 | const char *word; | ||
657 | int fd; | ||
658 | |||
659 | fd = serial_open(*arg++, /*quiet:*/ false); | ||
660 | if (fd < 0) | ||
661 | exit(201); | ||
662 | |||
663 | serial_ctl(fd, CTL_GET, &serinfo); | ||
664 | |||
665 | if (opts & OPT_ZERO) | ||
666 | serinfo.flags = 0; | ||
667 | |||
668 | while (*arg) { | ||
669 | int invert; | ||
670 | |||
671 | word = *arg++; | ||
672 | invert = (*word == '^'); | ||
673 | word += invert; | ||
674 | |||
675 | cmd = find_cmd(word); | ||
676 | |||
677 | if (*arg == NULL && cmd_need_arg(cmd)) | ||
678 | bb_error_msg_and_die(bb_msg_requires_arg, word); | ||
679 | |||
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: | ||
690 | serinfo.flags &= ASYNC_SPD_MASK; | ||
691 | /* 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: | ||
708 | serinfo.port = get_numeric(*arg++); | ||
709 | break; | ||
710 | case CMD_IRQ: | ||
711 | serinfo.irq = get_numeric(*arg++); | ||
712 | break; | ||
713 | case CMD_DIVISOR: | ||
714 | serinfo.custom_divisor = get_numeric(*arg++); | ||
715 | break; | ||
716 | case CMD_UART: | ||
717 | serinfo.type = get_uart(*arg++); | ||
718 | break; | ||
719 | case CMD_BASE: | ||
720 | serinfo.baud_base = get_numeric(*arg++); | ||
721 | break; | ||
722 | case CMD_DELAY: | ||
723 | serinfo.close_delay = get_numeric(*arg++); | ||
724 | break; | ||
725 | case CMD_WAIT: | ||
726 | serinfo.closing_wait = get_wait(*arg++); | ||
727 | 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 | |||
739 | int setserial_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
740 | int setserial_main(int argc UNUSED_PARAM, char **argv) | ||
741 | { | ||
742 | int opts; | ||
743 | |||
744 | opt_complementary = "-1:b-aG:G-ab:a-bG"; | ||
745 | opts = getopt32(argv, "bGavzg"); | ||
746 | argv += optind; | ||
747 | |||
748 | if (!argv[1]) /* one arg only? */ | ||
749 | opts |= OPT_GET; | ||
750 | |||
751 | if (!(opts & OPT_GET)) { | ||
752 | serial_set(argv, opts); | ||
753 | argv[1] = NULL; | ||
754 | } | ||
755 | |||
756 | if (opts & (OPT_VERBOSE | OPT_GET)) { | ||
757 | do { | ||
758 | serial_get(*argv++, opts & OPT_MODE_MASK); | ||
759 | } while (*argv); | ||
760 | } | ||
761 | |||
762 | return EXIT_SUCCESS; | ||
763 | } | ||