setserial.c 16 KB

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