xref: /openbmc/obmc-console/console-server.c (revision 329a35f551c1b73545a7dddb1944792a3621ac4a)
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