setserial.c 16 KB

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