1d831f960SJeremy Kerr /** 2d831f960SJeremy Kerr * Console server process for OpenBMC 3d831f960SJeremy Kerr * 4d831f960SJeremy Kerr * Copyright © 2016 IBM Corporation <jk@ozlabs.org> 5d831f960SJeremy Kerr */ 6d831f960SJeremy Kerr 717217845SJeremy Kerr #define _GNU_SOURCE 817217845SJeremy Kerr 9329a35f5SJeremy Kerr #include <assert.h> 10*769cee1aSJeremy Kerr #include <errno.h> 11*769cee1aSJeremy Kerr #include <signal.h> 12d831f960SJeremy Kerr #include <stdint.h> 13d831f960SJeremy Kerr #include <stdbool.h> 14d831f960SJeremy Kerr #include <stdlib.h> 15d831f960SJeremy Kerr #include <stdio.h> 16d831f960SJeremy Kerr #include <fcntl.h> 17d831f960SJeremy Kerr #include <unistd.h> 18d831f960SJeremy Kerr #include <err.h> 19d831f960SJeremy Kerr #include <string.h> 20d831f960SJeremy Kerr #include <getopt.h> 2117217845SJeremy Kerr #include <limits.h> 22d831f960SJeremy Kerr 23d831f960SJeremy Kerr #include <sys/types.h> 24d831f960SJeremy Kerr #include <sys/poll.h> 25d831f960SJeremy Kerr 261a0e03b4SJeremy Kerr #include "console-server.h" 27d831f960SJeremy Kerr 281a0e03b4SJeremy Kerr struct console { 2917217845SJeremy Kerr const char *tty_kname; 3017217845SJeremy Kerr char *tty_sysfs_devnode; 3117217845SJeremy Kerr char *tty_dev; 32957818b4SJeremy Kerr int tty_sirq; 33957818b4SJeremy Kerr int tty_lpc_addr; 34d831f960SJeremy Kerr int tty_fd; 35329a35f5SJeremy Kerr 361a0e03b4SJeremy Kerr struct handler **handlers; 371a0e03b4SJeremy Kerr int n_handlers; 38329a35f5SJeremy Kerr 39329a35f5SJeremy Kerr struct poller **pollers; 40329a35f5SJeremy Kerr int n_pollers; 41329a35f5SJeremy Kerr 42329a35f5SJeremy Kerr struct pollfd *pollfds; 43d831f960SJeremy Kerr }; 44d831f960SJeremy Kerr 45329a35f5SJeremy Kerr struct poller { 46329a35f5SJeremy Kerr struct handler *handler; 47329a35f5SJeremy Kerr void *data; 48329a35f5SJeremy Kerr poller_fn_t fn; 49329a35f5SJeremy Kerr bool remove; 50329a35f5SJeremy Kerr }; 51329a35f5SJeremy Kerr 52329a35f5SJeremy Kerr /* we have one extra entry in the pollfds array for the VUART tty */ 53329a35f5SJeremy Kerr static const int n_internal_pollfds = 1; 54329a35f5SJeremy Kerr 55*769cee1aSJeremy Kerr /* state shared with the signal handler */ 56*769cee1aSJeremy Kerr static bool sigint; 57329a35f5SJeremy Kerr 58d831f960SJeremy Kerr static void usage(const char *progname) 59d831f960SJeremy Kerr { 60d831f960SJeremy Kerr fprintf(stderr, 61d831f960SJeremy Kerr "usage: %s [options]\n" 62d831f960SJeremy Kerr "\n" 63d831f960SJeremy Kerr "Options:\n" 6417217845SJeremy Kerr " --device <TTY> Use serial device TTY (eg, ttyS0)\n" 65d831f960SJeremy Kerr "", 66d831f960SJeremy Kerr progname); 67d831f960SJeremy Kerr } 68d831f960SJeremy Kerr 6917217845SJeremy Kerr /* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */ 701a0e03b4SJeremy Kerr static int tty_find_device(struct console *console) 7117217845SJeremy Kerr { 7217217845SJeremy Kerr char *tty_class_device_link; 7317217845SJeremy Kerr char *tty_device_tty_dir; 7417217845SJeremy Kerr char *tty_device_reldir; 7517217845SJeremy Kerr int rc; 7617217845SJeremy Kerr 7717217845SJeremy Kerr rc = -1; 7817217845SJeremy Kerr tty_class_device_link = NULL; 7917217845SJeremy Kerr tty_device_tty_dir = NULL; 8017217845SJeremy Kerr tty_device_reldir = NULL; 8117217845SJeremy Kerr 8217217845SJeremy Kerr rc = asprintf(&tty_class_device_link, 831a0e03b4SJeremy Kerr "/sys/class/tty/%s", console->tty_kname); 8417217845SJeremy Kerr if (rc < 0) 8517217845SJeremy Kerr return -1; 8617217845SJeremy Kerr 8717217845SJeremy Kerr tty_device_tty_dir = realpath(tty_class_device_link, NULL); 8817217845SJeremy Kerr if (rc < 0) { 891a0e03b4SJeremy Kerr warn("Can't query sysfs for device %s", console->tty_kname); 9017217845SJeremy Kerr goto out_free; 9117217845SJeremy Kerr } 9217217845SJeremy Kerr 9317217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 9417217845SJeremy Kerr if (rc < 0) 9517217845SJeremy Kerr goto out_free; 9617217845SJeremy Kerr 971a0e03b4SJeremy Kerr console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 981a0e03b4SJeremy Kerr if (!console->tty_sysfs_devnode) 991a0e03b4SJeremy Kerr warn("Can't find parent device for %s", console->tty_kname); 10017217845SJeremy Kerr 10117217845SJeremy Kerr 10217217845SJeremy Kerr /* todo: lookup from major/minor info in sysfs, in case udev has 10317217845SJeremy Kerr * renamed us */ 1041a0e03b4SJeremy Kerr rc = asprintf(&console->tty_dev, "/dev/%s", console->tty_kname); 10517217845SJeremy Kerr if (rc < 0) 10617217845SJeremy Kerr goto out_free; 10717217845SJeremy Kerr 10817217845SJeremy Kerr rc = 0; 10917217845SJeremy Kerr 11017217845SJeremy Kerr out_free: 11117217845SJeremy Kerr free(tty_class_device_link); 11217217845SJeremy Kerr free(tty_device_tty_dir); 11317217845SJeremy Kerr free(tty_device_reldir); 11417217845SJeremy Kerr return rc; 11517217845SJeremy Kerr } 11617217845SJeremy Kerr 1171a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name, 118957818b4SJeremy Kerr int value) 119957818b4SJeremy Kerr { 120957818b4SJeremy Kerr char *path; 121957818b4SJeremy Kerr FILE *fp; 122957818b4SJeremy Kerr int rc; 123957818b4SJeremy Kerr 1241a0e03b4SJeremy Kerr rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name); 125957818b4SJeremy Kerr if (rc < 0) 126957818b4SJeremy Kerr return -1; 127957818b4SJeremy Kerr 128957818b4SJeremy Kerr fp = fopen(path, "w"); 129957818b4SJeremy Kerr if (!fp) { 130957818b4SJeremy Kerr warn("Can't access attribute %s on device %s", 1311a0e03b4SJeremy Kerr name, console->tty_kname); 132957818b4SJeremy Kerr rc = -1; 133957818b4SJeremy Kerr goto out_free; 134957818b4SJeremy Kerr } 135957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 136957818b4SJeremy Kerr 137957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 138957818b4SJeremy Kerr if (rc < 0) 139957818b4SJeremy Kerr warn("Error writing to %s attribute of device %s", 1401a0e03b4SJeremy Kerr name, console->tty_kname); 141957818b4SJeremy Kerr fclose(fp); 142957818b4SJeremy Kerr 143957818b4SJeremy Kerr 144957818b4SJeremy Kerr 145957818b4SJeremy Kerr out_free: 146957818b4SJeremy Kerr free(path); 147957818b4SJeremy Kerr return rc; 148957818b4SJeremy Kerr } 149957818b4SJeremy Kerr 150d831f960SJeremy Kerr /** 151d831f960SJeremy Kerr * Open and initialise the serial device 152d831f960SJeremy Kerr */ 1531a0e03b4SJeremy Kerr static int tty_init_io(struct console *console) 154d831f960SJeremy Kerr { 1551a0e03b4SJeremy Kerr if (console->tty_sirq) 1561a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 1571a0e03b4SJeremy Kerr if (console->tty_lpc_addr) 1581a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 1591a0e03b4SJeremy Kerr console->tty_lpc_addr); 1601a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "enabled", 1); 161957818b4SJeremy Kerr 1621a0e03b4SJeremy Kerr console->tty_fd = open(console->tty_dev, O_RDWR); 1631a0e03b4SJeremy Kerr if (console->tty_fd <= 0) { 1641a0e03b4SJeremy Kerr warn("Can't open tty %s", console->tty_dev); 165d831f960SJeremy Kerr return -1; 166d831f960SJeremy Kerr } 167d831f960SJeremy Kerr 168d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 169d831f960SJeremy Kerr * we detect larger amounts of data 170d831f960SJeremy Kerr */ 1711a0e03b4SJeremy Kerr fcntl(console->tty_fd, F_SETFL, FNDELAY); 172d831f960SJeremy Kerr 173329a35f5SJeremy Kerr console->pollfds[console->n_pollers].fd = console->tty_fd; 174329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 175329a35f5SJeremy Kerr 176d831f960SJeremy Kerr return 0; 177d831f960SJeremy Kerr } 178d831f960SJeremy Kerr 1791a0e03b4SJeremy Kerr 1801a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 181d831f960SJeremy Kerr { 1821a0e03b4SJeremy Kerr return write_buf_to_fd(console->tty_fd, data, len); 183d831f960SJeremy Kerr } 184d831f960SJeremy Kerr 1851a0e03b4SJeremy Kerr static void handlers_init(struct console *console) 186d831f960SJeremy Kerr { 1871a0e03b4SJeremy Kerr extern struct handler *__start_handlers, *__stop_handlers; 1881a0e03b4SJeremy Kerr struct handler *handler; 1891a0e03b4SJeremy Kerr int i; 190d831f960SJeremy Kerr 1911a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 1921a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 193d831f960SJeremy Kerr 1941a0e03b4SJeremy Kerr printf("%d handler%s\n", console->n_handlers, 1951a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 196d831f960SJeremy Kerr 1971a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 1981a0e03b4SJeremy Kerr handler = console->handlers[i]; 1991a0e03b4SJeremy Kerr 2001a0e03b4SJeremy Kerr printf(" %s\n", handler->name); 2011a0e03b4SJeremy Kerr 2021a0e03b4SJeremy Kerr if (handler->init) 2031a0e03b4SJeremy Kerr handler->init(handler, console); 204d831f960SJeremy Kerr } 205d831f960SJeremy Kerr } 206d831f960SJeremy Kerr 2071a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 208d831f960SJeremy Kerr { 2091a0e03b4SJeremy Kerr struct handler *handler; 2101a0e03b4SJeremy Kerr int i; 2111a0e03b4SJeremy Kerr 2121a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2131a0e03b4SJeremy Kerr handler = console->handlers[i]; 2141a0e03b4SJeremy Kerr if (handler->fini) 2151a0e03b4SJeremy Kerr handler->fini(handler); 2161a0e03b4SJeremy Kerr } 217d831f960SJeremy Kerr } 218d831f960SJeremy Kerr 2191a0e03b4SJeremy Kerr static int handlers_data_in(struct console *console, uint8_t *buf, size_t len) 220d831f960SJeremy Kerr { 2211a0e03b4SJeremy Kerr struct handler *handler; 2221a0e03b4SJeremy Kerr int i, rc, tmp; 223d831f960SJeremy Kerr 2241a0e03b4SJeremy Kerr rc = 0; 2251a0e03b4SJeremy Kerr 2261a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2271a0e03b4SJeremy Kerr handler = console->handlers[i]; 2281a0e03b4SJeremy Kerr 2291a0e03b4SJeremy Kerr if (!handler->data_in) 2301a0e03b4SJeremy Kerr continue; 2311a0e03b4SJeremy Kerr 2321a0e03b4SJeremy Kerr tmp = handler->data_in(handler, buf, len); 2331a0e03b4SJeremy Kerr if (tmp == HANDLER_EXIT) 2341a0e03b4SJeremy Kerr rc = 1; 235d831f960SJeremy Kerr } 236d831f960SJeremy Kerr 2371a0e03b4SJeremy Kerr return rc; 238329a35f5SJeremy Kerr 239d831f960SJeremy Kerr } 240d831f960SJeremy Kerr 241329a35f5SJeremy Kerr struct poller *console_register_poller(struct console *console, 242329a35f5SJeremy Kerr struct handler *handler, poller_fn_t poller_fn, 243329a35f5SJeremy Kerr int fd, int events, void *data) 244d831f960SJeremy Kerr { 245329a35f5SJeremy Kerr struct poller *poller; 246329a35f5SJeremy Kerr int n; 247329a35f5SJeremy Kerr 248329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 249329a35f5SJeremy Kerr poller->remove = false; 250329a35f5SJeremy Kerr poller->handler = handler; 251329a35f5SJeremy Kerr poller->fn = poller_fn; 252329a35f5SJeremy Kerr poller->data = data; 253329a35f5SJeremy Kerr 254329a35f5SJeremy Kerr /* add one to our pollers array */ 255329a35f5SJeremy Kerr n = console->n_pollers++; 256329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 257329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 258329a35f5SJeremy Kerr 259329a35f5SJeremy Kerr console->pollers[n] = poller; 260329a35f5SJeremy Kerr 261329a35f5SJeremy Kerr /* increase pollfds array too */ 262329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 263329a35f5SJeremy Kerr sizeof(*console->pollfds) * 264329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers)); 265329a35f5SJeremy Kerr 266329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 267329a35f5SJeremy Kerr memcpy(&console->pollfds[n+n_internal_pollfds], 268329a35f5SJeremy Kerr &console->pollfds[n], 269329a35f5SJeremy Kerr sizeof(*console->pollfds) * n_internal_pollfds); 270329a35f5SJeremy Kerr 271329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 272329a35f5SJeremy Kerr console->pollfds[n].events = events; 273329a35f5SJeremy Kerr 274329a35f5SJeremy Kerr return poller; 275329a35f5SJeremy Kerr } 276329a35f5SJeremy Kerr 277329a35f5SJeremy Kerr void console_unregister_poller(struct console *console, 278329a35f5SJeremy Kerr struct poller *poller) 279329a35f5SJeremy Kerr { 280329a35f5SJeremy Kerr int i; 281329a35f5SJeremy Kerr 282329a35f5SJeremy Kerr /* find the entry in our pollers array */ 283329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 284329a35f5SJeremy Kerr if (console->pollers[i] == poller) 285329a35f5SJeremy Kerr break; 286329a35f5SJeremy Kerr 287329a35f5SJeremy Kerr assert(i < console->n_pollers); 288329a35f5SJeremy Kerr 289329a35f5SJeremy Kerr console->n_pollers--; 290329a35f5SJeremy Kerr 291329a35f5SJeremy Kerr /* remove the item from the pollers array... */ 292329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i+1], 293329a35f5SJeremy Kerr sizeof(*console->pollers) 294329a35f5SJeremy Kerr * (console->n_pollers - i)); 295329a35f5SJeremy Kerr 296329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 297329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 298329a35f5SJeremy Kerr 299329a35f5SJeremy Kerr /* ... and the pollfds array */ 300329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i+1], 301329a35f5SJeremy Kerr sizeof(*console->pollfds) * 302329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers - i)); 303329a35f5SJeremy Kerr 304329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 305329a35f5SJeremy Kerr sizeof(*console->pollfds) * 306329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers)); 307329a35f5SJeremy Kerr 308329a35f5SJeremy Kerr 309329a35f5SJeremy Kerr free(poller); 310329a35f5SJeremy Kerr } 311329a35f5SJeremy Kerr 312329a35f5SJeremy Kerr static int call_pollers(struct console *console) 313329a35f5SJeremy Kerr { 314329a35f5SJeremy Kerr struct poller *poller; 315329a35f5SJeremy Kerr struct pollfd *pollfd; 316329a35f5SJeremy Kerr enum poller_ret prc; 317329a35f5SJeremy Kerr int i, rc; 318d831f960SJeremy Kerr 3191a0e03b4SJeremy Kerr rc = 0; 3201a0e03b4SJeremy Kerr 321329a35f5SJeremy Kerr /* 322329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 323329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 324329a35f5SJeremy Kerr */ 325329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 326329a35f5SJeremy Kerr poller = console->pollers[i]; 327329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 3281a0e03b4SJeremy Kerr 329329a35f5SJeremy Kerr if (!pollfd->revents) 3301a0e03b4SJeremy Kerr continue; 3311a0e03b4SJeremy Kerr 332329a35f5SJeremy Kerr prc = poller->fn(poller->handler, pollfd->revents, 333329a35f5SJeremy Kerr poller->data); 334329a35f5SJeremy Kerr if (prc == POLLER_EXIT) 335329a35f5SJeremy Kerr rc = -1; 336329a35f5SJeremy Kerr else if (prc == POLLER_REMOVE) 337329a35f5SJeremy Kerr poller->remove = true; 338329a35f5SJeremy Kerr } 339329a35f5SJeremy Kerr 340329a35f5SJeremy Kerr /** 341329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 342329a35f5SJeremy Kerr * the array will have changed 343329a35f5SJeremy Kerr */ 344329a35f5SJeremy Kerr for (;;) { 345329a35f5SJeremy Kerr bool removed = false; 346329a35f5SJeremy Kerr 347329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 348329a35f5SJeremy Kerr poller = console->pollers[i]; 349329a35f5SJeremy Kerr if (poller->remove) { 350329a35f5SJeremy Kerr console_unregister_poller(console, poller); 351329a35f5SJeremy Kerr removed = true; 352329a35f5SJeremy Kerr break; 353329a35f5SJeremy Kerr } 354329a35f5SJeremy Kerr } 355329a35f5SJeremy Kerr if (!removed) 356329a35f5SJeremy Kerr break; 3571a0e03b4SJeremy Kerr } 3581a0e03b4SJeremy Kerr 3591a0e03b4SJeremy Kerr return rc; 3601a0e03b4SJeremy Kerr } 3611a0e03b4SJeremy Kerr 362*769cee1aSJeremy Kerr static void sighandler(int signal) 363*769cee1aSJeremy Kerr { 364*769cee1aSJeremy Kerr if (signal == SIGINT) 365*769cee1aSJeremy Kerr sigint = true; 366*769cee1aSJeremy Kerr } 367*769cee1aSJeremy Kerr 3681a0e03b4SJeremy Kerr int run_console(struct console *console) 3691a0e03b4SJeremy Kerr { 370*769cee1aSJeremy Kerr sighandler_t sighandler_save; 371329a35f5SJeremy Kerr int rc; 372d831f960SJeremy Kerr 373*769cee1aSJeremy Kerr sighandler_save = signal(SIGINT, sighandler); 374*769cee1aSJeremy Kerr 375*769cee1aSJeremy Kerr rc = 0; 376*769cee1aSJeremy Kerr 377d831f960SJeremy Kerr for (;;) { 378d831f960SJeremy Kerr uint8_t buf[4096]; 379d831f960SJeremy Kerr 380*769cee1aSJeremy Kerr if (sigint) { 381*769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 382*769cee1aSJeremy Kerr break; 383*769cee1aSJeremy Kerr } 384*769cee1aSJeremy Kerr 385329a35f5SJeremy Kerr rc = poll(console->pollfds, 386329a35f5SJeremy Kerr console->n_pollers + n_internal_pollfds, -1); 387d831f960SJeremy Kerr if (rc < 0) { 388*769cee1aSJeremy Kerr if (errno == EINTR) { 389*769cee1aSJeremy Kerr continue; 390*769cee1aSJeremy Kerr } else { 391d831f960SJeremy Kerr warn("poll error"); 392*769cee1aSJeremy Kerr break; 393*769cee1aSJeremy Kerr } 394d831f960SJeremy Kerr } 395d831f960SJeremy Kerr 396329a35f5SJeremy Kerr /* process internal fd first */ 397329a35f5SJeremy Kerr BUILD_ASSERT(n_internal_pollfds == 1); 398329a35f5SJeremy Kerr 399329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 4001a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 401d831f960SJeremy Kerr if (rc <= 0) { 402d831f960SJeremy Kerr warn("Error reading from tty device"); 403*769cee1aSJeremy Kerr rc = -1; 404*769cee1aSJeremy Kerr break; 405d831f960SJeremy Kerr } 4061a0e03b4SJeremy Kerr rc = handlers_data_in(console, buf, rc); 4071a0e03b4SJeremy Kerr if (rc) 408*769cee1aSJeremy Kerr break; 409d831f960SJeremy Kerr } 410d831f960SJeremy Kerr 411329a35f5SJeremy Kerr /* ... and then the pollers */ 412329a35f5SJeremy Kerr rc = call_pollers(console); 4131a0e03b4SJeremy Kerr if (rc) 414*769cee1aSJeremy Kerr break; 4151a0e03b4SJeremy Kerr } 416*769cee1aSJeremy Kerr 417*769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 418*769cee1aSJeremy Kerr 419*769cee1aSJeremy Kerr return rc ? -1 : 0; 4201a0e03b4SJeremy Kerr } 421d831f960SJeremy Kerr static const struct option options[] = { 422d831f960SJeremy Kerr { "device", required_argument, 0, 'd'}, 423957818b4SJeremy Kerr { "sirq", required_argument, 0, 's'}, 424957818b4SJeremy Kerr { "lpc-addr", required_argument, 0, 'l'}, 425d831f960SJeremy Kerr { }, 426d831f960SJeremy Kerr }; 427d831f960SJeremy Kerr 428d831f960SJeremy Kerr int main(int argc, char **argv) 429d831f960SJeremy Kerr { 4301a0e03b4SJeremy Kerr struct console *console; 431d831f960SJeremy Kerr int rc; 432d831f960SJeremy Kerr 4331a0e03b4SJeremy Kerr console = malloc(sizeof(struct console)); 4341a0e03b4SJeremy Kerr memset(console, 0, sizeof(*console)); 435957818b4SJeremy Kerr rc = -1; 436d831f960SJeremy Kerr 437d831f960SJeremy Kerr for (;;) { 438957818b4SJeremy Kerr char *endp; 439d831f960SJeremy Kerr int c, idx; 440d831f960SJeremy Kerr 441957818b4SJeremy Kerr c = getopt_long(argc, argv, "d:s:l:", options, &idx); 442d831f960SJeremy Kerr if (c == -1) 443d831f960SJeremy Kerr break; 444d831f960SJeremy Kerr 445d831f960SJeremy Kerr switch (c) { 446d831f960SJeremy Kerr case 'd': 4471a0e03b4SJeremy Kerr console->tty_kname = optarg; 448d831f960SJeremy Kerr break; 449957818b4SJeremy Kerr case 'l': 4501a0e03b4SJeremy Kerr console->tty_lpc_addr = strtoul(optarg, &endp, 0); 451957818b4SJeremy Kerr if (endp == optarg) { 452957818b4SJeremy Kerr warnx("Invalid sirq: '%s'", optarg); 453957818b4SJeremy Kerr goto out_free; 454957818b4SJeremy Kerr } 455957818b4SJeremy Kerr break; 456957818b4SJeremy Kerr 457957818b4SJeremy Kerr case 's': 4581a0e03b4SJeremy Kerr console->tty_sirq = strtoul(optarg, &endp, 0); 459957818b4SJeremy Kerr if (endp == optarg) { 460957818b4SJeremy Kerr warnx("Invalid sirq: '%s'", optarg); 461957818b4SJeremy Kerr goto out_free; 462957818b4SJeremy Kerr } 463957818b4SJeremy Kerr break; 464d831f960SJeremy Kerr 465d831f960SJeremy Kerr case 'h': 466d831f960SJeremy Kerr case '?': 467d831f960SJeremy Kerr usage(argv[0]); 468957818b4SJeremy Kerr rc = 0; 469957818b4SJeremy Kerr goto out_free; 470d831f960SJeremy Kerr } 471d831f960SJeremy Kerr } 472d831f960SJeremy Kerr 473329a35f5SJeremy Kerr console->pollfds = calloc(n_internal_pollfds, 474329a35f5SJeremy Kerr sizeof(*console->pollfds)); 475329a35f5SJeremy Kerr 4761a0e03b4SJeremy Kerr if (!console->tty_kname) { 477d831f960SJeremy Kerr fprintf(stderr, 478d831f960SJeremy Kerr "Error: No TTY device specified (use --device)\n"); 479d831f960SJeremy Kerr return EXIT_FAILURE; 480d831f960SJeremy Kerr } 481d831f960SJeremy Kerr 4821a0e03b4SJeremy Kerr rc = tty_find_device(console); 48317217845SJeremy Kerr if (rc) 48417217845SJeremy Kerr return EXIT_FAILURE; 48517217845SJeremy Kerr 4861a0e03b4SJeremy Kerr rc = tty_init_io(console); 487d831f960SJeremy Kerr if (rc) 488d831f960SJeremy Kerr return EXIT_FAILURE; 489d831f960SJeremy Kerr 4901a0e03b4SJeremy Kerr handlers_init(console); 491d831f960SJeremy Kerr 4921a0e03b4SJeremy Kerr rc = run_console(console); 493d831f960SJeremy Kerr 4941a0e03b4SJeremy Kerr handlers_fini(console); 495d831f960SJeremy Kerr 496957818b4SJeremy Kerr out_free: 4971a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 4981a0e03b4SJeremy Kerr free(console->tty_dev); 4991a0e03b4SJeremy Kerr free(console); 500d831f960SJeremy Kerr 501d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 502d831f960SJeremy Kerr } 503