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 9*329a35f5SJeremy Kerr #include <assert.h> 10d831f960SJeremy Kerr #include <stdint.h> 11d831f960SJeremy Kerr #include <stdbool.h> 12d831f960SJeremy Kerr #include <stdlib.h> 13d831f960SJeremy Kerr #include <stdio.h> 14d831f960SJeremy Kerr #include <fcntl.h> 15d831f960SJeremy Kerr #include <unistd.h> 16d831f960SJeremy Kerr #include <err.h> 17d831f960SJeremy Kerr #include <string.h> 18d831f960SJeremy Kerr #include <getopt.h> 1917217845SJeremy Kerr #include <limits.h> 20d831f960SJeremy Kerr 21d831f960SJeremy Kerr #include <sys/types.h> 22d831f960SJeremy Kerr #include <sys/poll.h> 23d831f960SJeremy Kerr 241a0e03b4SJeremy Kerr #include "console-server.h" 25d831f960SJeremy Kerr 261a0e03b4SJeremy Kerr struct console { 2717217845SJeremy Kerr const char *tty_kname; 2817217845SJeremy Kerr char *tty_sysfs_devnode; 2917217845SJeremy Kerr char *tty_dev; 30957818b4SJeremy Kerr int tty_sirq; 31957818b4SJeremy Kerr int tty_lpc_addr; 32d831f960SJeremy Kerr int tty_fd; 33*329a35f5SJeremy Kerr 341a0e03b4SJeremy Kerr struct handler **handlers; 351a0e03b4SJeremy Kerr int n_handlers; 36*329a35f5SJeremy Kerr 37*329a35f5SJeremy Kerr struct poller **pollers; 38*329a35f5SJeremy Kerr int n_pollers; 39*329a35f5SJeremy Kerr 40*329a35f5SJeremy Kerr struct pollfd *pollfds; 41d831f960SJeremy Kerr }; 42d831f960SJeremy Kerr 43*329a35f5SJeremy Kerr struct poller { 44*329a35f5SJeremy Kerr struct handler *handler; 45*329a35f5SJeremy Kerr void *data; 46*329a35f5SJeremy Kerr poller_fn_t fn; 47*329a35f5SJeremy Kerr bool remove; 48*329a35f5SJeremy Kerr }; 49*329a35f5SJeremy Kerr 50*329a35f5SJeremy Kerr /* we have one extra entry in the pollfds array for the VUART tty */ 51*329a35f5SJeremy Kerr static const int n_internal_pollfds = 1; 52*329a35f5SJeremy Kerr 53*329a35f5SJeremy Kerr 54d831f960SJeremy Kerr static void usage(const char *progname) 55d831f960SJeremy Kerr { 56d831f960SJeremy Kerr fprintf(stderr, 57d831f960SJeremy Kerr "usage: %s [options]\n" 58d831f960SJeremy Kerr "\n" 59d831f960SJeremy Kerr "Options:\n" 6017217845SJeremy Kerr " --device <TTY> Use serial device TTY (eg, ttyS0)\n" 61d831f960SJeremy Kerr "", 62d831f960SJeremy Kerr progname); 63d831f960SJeremy Kerr } 64d831f960SJeremy Kerr 6517217845SJeremy Kerr /* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */ 661a0e03b4SJeremy Kerr static int tty_find_device(struct console *console) 6717217845SJeremy Kerr { 6817217845SJeremy Kerr char *tty_class_device_link; 6917217845SJeremy Kerr char *tty_device_tty_dir; 7017217845SJeremy Kerr char *tty_device_reldir; 7117217845SJeremy Kerr int rc; 7217217845SJeremy Kerr 7317217845SJeremy Kerr rc = -1; 7417217845SJeremy Kerr tty_class_device_link = NULL; 7517217845SJeremy Kerr tty_device_tty_dir = NULL; 7617217845SJeremy Kerr tty_device_reldir = NULL; 7717217845SJeremy Kerr 7817217845SJeremy Kerr rc = asprintf(&tty_class_device_link, 791a0e03b4SJeremy Kerr "/sys/class/tty/%s", console->tty_kname); 8017217845SJeremy Kerr if (rc < 0) 8117217845SJeremy Kerr return -1; 8217217845SJeremy Kerr 8317217845SJeremy Kerr tty_device_tty_dir = realpath(tty_class_device_link, NULL); 8417217845SJeremy Kerr if (rc < 0) { 851a0e03b4SJeremy Kerr warn("Can't query sysfs for device %s", console->tty_kname); 8617217845SJeremy Kerr goto out_free; 8717217845SJeremy Kerr } 8817217845SJeremy Kerr 8917217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 9017217845SJeremy Kerr if (rc < 0) 9117217845SJeremy Kerr goto out_free; 9217217845SJeremy Kerr 931a0e03b4SJeremy Kerr console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 941a0e03b4SJeremy Kerr if (!console->tty_sysfs_devnode) 951a0e03b4SJeremy Kerr warn("Can't find parent device for %s", console->tty_kname); 9617217845SJeremy Kerr 9717217845SJeremy Kerr 9817217845SJeremy Kerr /* todo: lookup from major/minor info in sysfs, in case udev has 9917217845SJeremy Kerr * renamed us */ 1001a0e03b4SJeremy Kerr rc = asprintf(&console->tty_dev, "/dev/%s", console->tty_kname); 10117217845SJeremy Kerr if (rc < 0) 10217217845SJeremy Kerr goto out_free; 10317217845SJeremy Kerr 10417217845SJeremy Kerr rc = 0; 10517217845SJeremy Kerr 10617217845SJeremy Kerr out_free: 10717217845SJeremy Kerr free(tty_class_device_link); 10817217845SJeremy Kerr free(tty_device_tty_dir); 10917217845SJeremy Kerr free(tty_device_reldir); 11017217845SJeremy Kerr return rc; 11117217845SJeremy Kerr } 11217217845SJeremy Kerr 1131a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name, 114957818b4SJeremy Kerr int value) 115957818b4SJeremy Kerr { 116957818b4SJeremy Kerr char *path; 117957818b4SJeremy Kerr FILE *fp; 118957818b4SJeremy Kerr int rc; 119957818b4SJeremy Kerr 1201a0e03b4SJeremy Kerr rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name); 121957818b4SJeremy Kerr if (rc < 0) 122957818b4SJeremy Kerr return -1; 123957818b4SJeremy Kerr 124957818b4SJeremy Kerr fp = fopen(path, "w"); 125957818b4SJeremy Kerr if (!fp) { 126957818b4SJeremy Kerr warn("Can't access attribute %s on device %s", 1271a0e03b4SJeremy Kerr name, console->tty_kname); 128957818b4SJeremy Kerr rc = -1; 129957818b4SJeremy Kerr goto out_free; 130957818b4SJeremy Kerr } 131957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 132957818b4SJeremy Kerr 133957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 134957818b4SJeremy Kerr if (rc < 0) 135957818b4SJeremy Kerr warn("Error writing to %s attribute of device %s", 1361a0e03b4SJeremy Kerr name, console->tty_kname); 137957818b4SJeremy Kerr fclose(fp); 138957818b4SJeremy Kerr 139957818b4SJeremy Kerr 140957818b4SJeremy Kerr 141957818b4SJeremy Kerr out_free: 142957818b4SJeremy Kerr free(path); 143957818b4SJeremy Kerr return rc; 144957818b4SJeremy Kerr } 145957818b4SJeremy Kerr 146d831f960SJeremy Kerr /** 147d831f960SJeremy Kerr * Open and initialise the serial device 148d831f960SJeremy Kerr */ 1491a0e03b4SJeremy Kerr static int tty_init_io(struct console *console) 150d831f960SJeremy Kerr { 1511a0e03b4SJeremy Kerr if (console->tty_sirq) 1521a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 1531a0e03b4SJeremy Kerr if (console->tty_lpc_addr) 1541a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 1551a0e03b4SJeremy Kerr console->tty_lpc_addr); 1561a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "enabled", 1); 157957818b4SJeremy Kerr 1581a0e03b4SJeremy Kerr console->tty_fd = open(console->tty_dev, O_RDWR); 1591a0e03b4SJeremy Kerr if (console->tty_fd <= 0) { 1601a0e03b4SJeremy Kerr warn("Can't open tty %s", console->tty_dev); 161d831f960SJeremy Kerr return -1; 162d831f960SJeremy Kerr } 163d831f960SJeremy Kerr 164d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 165d831f960SJeremy Kerr * we detect larger amounts of data 166d831f960SJeremy Kerr */ 1671a0e03b4SJeremy Kerr fcntl(console->tty_fd, F_SETFL, FNDELAY); 168d831f960SJeremy Kerr 169*329a35f5SJeremy Kerr console->pollfds[console->n_pollers].fd = console->tty_fd; 170*329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 171*329a35f5SJeremy Kerr 172d831f960SJeremy Kerr return 0; 173d831f960SJeremy Kerr } 174d831f960SJeremy Kerr 1751a0e03b4SJeremy Kerr 1761a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 177d831f960SJeremy Kerr { 1781a0e03b4SJeremy Kerr return write_buf_to_fd(console->tty_fd, data, len); 179d831f960SJeremy Kerr } 180d831f960SJeremy Kerr 1811a0e03b4SJeremy Kerr static void handlers_init(struct console *console) 182d831f960SJeremy Kerr { 1831a0e03b4SJeremy Kerr extern struct handler *__start_handlers, *__stop_handlers; 1841a0e03b4SJeremy Kerr struct handler *handler; 1851a0e03b4SJeremy Kerr int i; 186d831f960SJeremy Kerr 1871a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 1881a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 189d831f960SJeremy Kerr 1901a0e03b4SJeremy Kerr printf("%d handler%s\n", console->n_handlers, 1911a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 192d831f960SJeremy Kerr 1931a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 1941a0e03b4SJeremy Kerr handler = console->handlers[i]; 1951a0e03b4SJeremy Kerr 1961a0e03b4SJeremy Kerr printf(" %s\n", handler->name); 1971a0e03b4SJeremy Kerr 1981a0e03b4SJeremy Kerr if (handler->init) 1991a0e03b4SJeremy Kerr handler->init(handler, console); 200d831f960SJeremy Kerr } 201d831f960SJeremy Kerr } 202d831f960SJeremy Kerr 2031a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 204d831f960SJeremy Kerr { 2051a0e03b4SJeremy Kerr struct handler *handler; 2061a0e03b4SJeremy Kerr int i; 2071a0e03b4SJeremy Kerr 2081a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2091a0e03b4SJeremy Kerr handler = console->handlers[i]; 2101a0e03b4SJeremy Kerr if (handler->fini) 2111a0e03b4SJeremy Kerr handler->fini(handler); 2121a0e03b4SJeremy Kerr } 213d831f960SJeremy Kerr } 214d831f960SJeremy Kerr 2151a0e03b4SJeremy Kerr static int handlers_data_in(struct console *console, uint8_t *buf, size_t len) 216d831f960SJeremy Kerr { 2171a0e03b4SJeremy Kerr struct handler *handler; 2181a0e03b4SJeremy Kerr int i, rc, tmp; 219d831f960SJeremy Kerr 2201a0e03b4SJeremy Kerr rc = 0; 2211a0e03b4SJeremy Kerr 2221a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2231a0e03b4SJeremy Kerr handler = console->handlers[i]; 2241a0e03b4SJeremy Kerr 2251a0e03b4SJeremy Kerr if (!handler->data_in) 2261a0e03b4SJeremy Kerr continue; 2271a0e03b4SJeremy Kerr 2281a0e03b4SJeremy Kerr tmp = handler->data_in(handler, buf, len); 2291a0e03b4SJeremy Kerr if (tmp == HANDLER_EXIT) 2301a0e03b4SJeremy Kerr rc = 1; 231d831f960SJeremy Kerr } 232d831f960SJeremy Kerr 2331a0e03b4SJeremy Kerr return rc; 234*329a35f5SJeremy Kerr 235d831f960SJeremy Kerr } 236d831f960SJeremy Kerr 237*329a35f5SJeremy Kerr struct poller *console_register_poller(struct console *console, 238*329a35f5SJeremy Kerr struct handler *handler, poller_fn_t poller_fn, 239*329a35f5SJeremy Kerr int fd, int events, void *data) 240d831f960SJeremy Kerr { 241*329a35f5SJeremy Kerr struct poller *poller; 242*329a35f5SJeremy Kerr int n; 243*329a35f5SJeremy Kerr 244*329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 245*329a35f5SJeremy Kerr poller->remove = false; 246*329a35f5SJeremy Kerr poller->handler = handler; 247*329a35f5SJeremy Kerr poller->fn = poller_fn; 248*329a35f5SJeremy Kerr poller->data = data; 249*329a35f5SJeremy Kerr 250*329a35f5SJeremy Kerr /* add one to our pollers array */ 251*329a35f5SJeremy Kerr n = console->n_pollers++; 252*329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 253*329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 254*329a35f5SJeremy Kerr 255*329a35f5SJeremy Kerr console->pollers[n] = poller; 256*329a35f5SJeremy Kerr 257*329a35f5SJeremy Kerr /* increase pollfds array too */ 258*329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 259*329a35f5SJeremy Kerr sizeof(*console->pollfds) * 260*329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers)); 261*329a35f5SJeremy Kerr 262*329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 263*329a35f5SJeremy Kerr memcpy(&console->pollfds[n+n_internal_pollfds], 264*329a35f5SJeremy Kerr &console->pollfds[n], 265*329a35f5SJeremy Kerr sizeof(*console->pollfds) * n_internal_pollfds); 266*329a35f5SJeremy Kerr 267*329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 268*329a35f5SJeremy Kerr console->pollfds[n].events = events; 269*329a35f5SJeremy Kerr 270*329a35f5SJeremy Kerr return poller; 271*329a35f5SJeremy Kerr } 272*329a35f5SJeremy Kerr 273*329a35f5SJeremy Kerr void console_unregister_poller(struct console *console, 274*329a35f5SJeremy Kerr struct poller *poller) 275*329a35f5SJeremy Kerr { 276*329a35f5SJeremy Kerr int i; 277*329a35f5SJeremy Kerr 278*329a35f5SJeremy Kerr /* find the entry in our pollers array */ 279*329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 280*329a35f5SJeremy Kerr if (console->pollers[i] == poller) 281*329a35f5SJeremy Kerr break; 282*329a35f5SJeremy Kerr 283*329a35f5SJeremy Kerr assert(i < console->n_pollers); 284*329a35f5SJeremy Kerr 285*329a35f5SJeremy Kerr console->n_pollers--; 286*329a35f5SJeremy Kerr 287*329a35f5SJeremy Kerr /* remove the item from the pollers array... */ 288*329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i+1], 289*329a35f5SJeremy Kerr sizeof(*console->pollers) 290*329a35f5SJeremy Kerr * (console->n_pollers - i)); 291*329a35f5SJeremy Kerr 292*329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 293*329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 294*329a35f5SJeremy Kerr 295*329a35f5SJeremy Kerr /* ... and the pollfds array */ 296*329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i+1], 297*329a35f5SJeremy Kerr sizeof(*console->pollfds) * 298*329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers - i)); 299*329a35f5SJeremy Kerr 300*329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 301*329a35f5SJeremy Kerr sizeof(*console->pollfds) * 302*329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers)); 303*329a35f5SJeremy Kerr 304*329a35f5SJeremy Kerr 305*329a35f5SJeremy Kerr free(poller); 306*329a35f5SJeremy Kerr } 307*329a35f5SJeremy Kerr 308*329a35f5SJeremy Kerr static int call_pollers(struct console *console) 309*329a35f5SJeremy Kerr { 310*329a35f5SJeremy Kerr struct poller *poller; 311*329a35f5SJeremy Kerr struct pollfd *pollfd; 312*329a35f5SJeremy Kerr enum poller_ret prc; 313*329a35f5SJeremy Kerr int i, rc; 314d831f960SJeremy Kerr 3151a0e03b4SJeremy Kerr rc = 0; 3161a0e03b4SJeremy Kerr 317*329a35f5SJeremy Kerr /* 318*329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 319*329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 320*329a35f5SJeremy Kerr */ 321*329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 322*329a35f5SJeremy Kerr poller = console->pollers[i]; 323*329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 3241a0e03b4SJeremy Kerr 325*329a35f5SJeremy Kerr if (!pollfd->revents) 3261a0e03b4SJeremy Kerr continue; 3271a0e03b4SJeremy Kerr 328*329a35f5SJeremy Kerr prc = poller->fn(poller->handler, pollfd->revents, 329*329a35f5SJeremy Kerr poller->data); 330*329a35f5SJeremy Kerr if (prc == POLLER_EXIT) 331*329a35f5SJeremy Kerr rc = -1; 332*329a35f5SJeremy Kerr else if (prc == POLLER_REMOVE) 333*329a35f5SJeremy Kerr poller->remove = true; 334*329a35f5SJeremy Kerr } 335*329a35f5SJeremy Kerr 336*329a35f5SJeremy Kerr /** 337*329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 338*329a35f5SJeremy Kerr * the array will have changed 339*329a35f5SJeremy Kerr */ 340*329a35f5SJeremy Kerr for (;;) { 341*329a35f5SJeremy Kerr bool removed = false; 342*329a35f5SJeremy Kerr 343*329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 344*329a35f5SJeremy Kerr poller = console->pollers[i]; 345*329a35f5SJeremy Kerr if (poller->remove) { 346*329a35f5SJeremy Kerr console_unregister_poller(console, poller); 347*329a35f5SJeremy Kerr removed = true; 348*329a35f5SJeremy Kerr break; 349*329a35f5SJeremy Kerr } 350*329a35f5SJeremy Kerr } 351*329a35f5SJeremy Kerr if (!removed) 352*329a35f5SJeremy Kerr break; 3531a0e03b4SJeremy Kerr } 3541a0e03b4SJeremy Kerr 3551a0e03b4SJeremy Kerr return rc; 3561a0e03b4SJeremy Kerr } 3571a0e03b4SJeremy Kerr 3581a0e03b4SJeremy Kerr int run_console(struct console *console) 3591a0e03b4SJeremy Kerr { 360*329a35f5SJeremy Kerr int rc; 361d831f960SJeremy Kerr 362d831f960SJeremy Kerr for (;;) { 363d831f960SJeremy Kerr uint8_t buf[4096]; 364d831f960SJeremy Kerr 365*329a35f5SJeremy Kerr rc = poll(console->pollfds, 366*329a35f5SJeremy Kerr console->n_pollers + n_internal_pollfds, -1); 367d831f960SJeremy Kerr if (rc < 0) { 368d831f960SJeremy Kerr warn("poll error"); 369d831f960SJeremy Kerr return -1; 370d831f960SJeremy Kerr } 371d831f960SJeremy Kerr 372*329a35f5SJeremy Kerr /* process internal fd first */ 373*329a35f5SJeremy Kerr BUILD_ASSERT(n_internal_pollfds == 1); 374*329a35f5SJeremy Kerr 375*329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 3761a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 377d831f960SJeremy Kerr if (rc <= 0) { 378d831f960SJeremy Kerr warn("Error reading from tty device"); 379d831f960SJeremy Kerr return -1; 380d831f960SJeremy Kerr } 3811a0e03b4SJeremy Kerr rc = handlers_data_in(console, buf, rc); 3821a0e03b4SJeremy Kerr if (rc) 383d831f960SJeremy Kerr return 0; 384d831f960SJeremy Kerr } 385d831f960SJeremy Kerr 386*329a35f5SJeremy Kerr /* ... and then the pollers */ 387*329a35f5SJeremy Kerr rc = call_pollers(console); 3881a0e03b4SJeremy Kerr if (rc) 3891a0e03b4SJeremy Kerr return 0; 3901a0e03b4SJeremy Kerr } 3911a0e03b4SJeremy Kerr } 392d831f960SJeremy Kerr static const struct option options[] = { 393d831f960SJeremy Kerr { "device", required_argument, 0, 'd'}, 394957818b4SJeremy Kerr { "sirq", required_argument, 0, 's'}, 395957818b4SJeremy Kerr { "lpc-addr", required_argument, 0, 'l'}, 396d831f960SJeremy Kerr { }, 397d831f960SJeremy Kerr }; 398d831f960SJeremy Kerr 399d831f960SJeremy Kerr int main(int argc, char **argv) 400d831f960SJeremy Kerr { 4011a0e03b4SJeremy Kerr struct console *console; 402d831f960SJeremy Kerr int rc; 403d831f960SJeremy Kerr 4041a0e03b4SJeremy Kerr console = malloc(sizeof(struct console)); 4051a0e03b4SJeremy Kerr memset(console, 0, sizeof(*console)); 406957818b4SJeremy Kerr rc = -1; 407d831f960SJeremy Kerr 408d831f960SJeremy Kerr for (;;) { 409957818b4SJeremy Kerr char *endp; 410d831f960SJeremy Kerr int c, idx; 411d831f960SJeremy Kerr 412957818b4SJeremy Kerr c = getopt_long(argc, argv, "d:s:l:", options, &idx); 413d831f960SJeremy Kerr if (c == -1) 414d831f960SJeremy Kerr break; 415d831f960SJeremy Kerr 416d831f960SJeremy Kerr switch (c) { 417d831f960SJeremy Kerr case 'd': 4181a0e03b4SJeremy Kerr console->tty_kname = optarg; 419d831f960SJeremy Kerr break; 420957818b4SJeremy Kerr case 'l': 4211a0e03b4SJeremy Kerr console->tty_lpc_addr = strtoul(optarg, &endp, 0); 422957818b4SJeremy Kerr if (endp == optarg) { 423957818b4SJeremy Kerr warnx("Invalid sirq: '%s'", optarg); 424957818b4SJeremy Kerr goto out_free; 425957818b4SJeremy Kerr } 426957818b4SJeremy Kerr break; 427957818b4SJeremy Kerr 428957818b4SJeremy Kerr case 's': 4291a0e03b4SJeremy Kerr console->tty_sirq = strtoul(optarg, &endp, 0); 430957818b4SJeremy Kerr if (endp == optarg) { 431957818b4SJeremy Kerr warnx("Invalid sirq: '%s'", optarg); 432957818b4SJeremy Kerr goto out_free; 433957818b4SJeremy Kerr } 434957818b4SJeremy Kerr break; 435d831f960SJeremy Kerr 436d831f960SJeremy Kerr case 'h': 437d831f960SJeremy Kerr case '?': 438d831f960SJeremy Kerr usage(argv[0]); 439957818b4SJeremy Kerr rc = 0; 440957818b4SJeremy Kerr goto out_free; 441d831f960SJeremy Kerr } 442d831f960SJeremy Kerr } 443d831f960SJeremy Kerr 444*329a35f5SJeremy Kerr console->pollfds = calloc(n_internal_pollfds, 445*329a35f5SJeremy Kerr sizeof(*console->pollfds)); 446*329a35f5SJeremy Kerr 4471a0e03b4SJeremy Kerr if (!console->tty_kname) { 448d831f960SJeremy Kerr fprintf(stderr, 449d831f960SJeremy Kerr "Error: No TTY device specified (use --device)\n"); 450d831f960SJeremy Kerr return EXIT_FAILURE; 451d831f960SJeremy Kerr } 452d831f960SJeremy Kerr 4531a0e03b4SJeremy Kerr rc = tty_find_device(console); 45417217845SJeremy Kerr if (rc) 45517217845SJeremy Kerr return EXIT_FAILURE; 45617217845SJeremy Kerr 4571a0e03b4SJeremy Kerr rc = tty_init_io(console); 458d831f960SJeremy Kerr if (rc) 459d831f960SJeremy Kerr return EXIT_FAILURE; 460d831f960SJeremy Kerr 4611a0e03b4SJeremy Kerr handlers_init(console); 462d831f960SJeremy Kerr 4631a0e03b4SJeremy Kerr rc = run_console(console); 464d831f960SJeremy Kerr 4651a0e03b4SJeremy Kerr handlers_fini(console); 466d831f960SJeremy Kerr 467957818b4SJeremy Kerr out_free: 4681a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 4691a0e03b4SJeremy Kerr free(console->tty_dev); 4701a0e03b4SJeremy Kerr free(console); 471d831f960SJeremy Kerr 472d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 473d831f960SJeremy Kerr } 474