xref: /freebsd/usr.sbin/bhyve/uart_backend.c (revision e10b9d66)
1d1c5d0cfSMark Johnston /*-
2d1c5d0cfSMark Johnston  * SPDX-License-Identifier: BSD-2-Clause
3d1c5d0cfSMark Johnston  *
4d1c5d0cfSMark Johnston  * Copyright (c) 2012 NetApp, Inc.
5d1c5d0cfSMark Johnston  * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
6d1c5d0cfSMark Johnston  * All rights reserved.
7d1c5d0cfSMark Johnston  *
8d1c5d0cfSMark Johnston  * Redistribution and use in source and binary forms, with or without
9d1c5d0cfSMark Johnston  * modification, are permitted provided that the following conditions
10d1c5d0cfSMark Johnston  * are met:
11d1c5d0cfSMark Johnston  * 1. Redistributions of source code must retain the above copyright
12d1c5d0cfSMark Johnston  *    notice, this list of conditions and the following disclaimer.
13d1c5d0cfSMark Johnston  * 2. Redistributions in binary form must reproduce the above copyright
14d1c5d0cfSMark Johnston  *    notice, this list of conditions and the following disclaimer in the
15d1c5d0cfSMark Johnston  *    documentation and/or other materials provided with the distribution.
16d1c5d0cfSMark Johnston  *
17d1c5d0cfSMark Johnston  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
18d1c5d0cfSMark Johnston  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19d1c5d0cfSMark Johnston  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20d1c5d0cfSMark Johnston  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
21d1c5d0cfSMark Johnston  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22d1c5d0cfSMark Johnston  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23d1c5d0cfSMark Johnston  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24d1c5d0cfSMark Johnston  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25d1c5d0cfSMark Johnston  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26d1c5d0cfSMark Johnston  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27d1c5d0cfSMark Johnston  * SUCH DAMAGE.
28d1c5d0cfSMark Johnston  */
29d1c5d0cfSMark Johnston 
30d1c5d0cfSMark Johnston #include <sys/types.h>
31d1c5d0cfSMark Johnston 
32d1c5d0cfSMark Johnston #include <machine/vmm.h>
33d1c5d0cfSMark Johnston #include <machine/vmm_snapshot.h>
34d1c5d0cfSMark Johnston 
35d1c5d0cfSMark Johnston #include <assert.h>
36d1c5d0cfSMark Johnston #include <capsicum_helpers.h>
37d1c5d0cfSMark Johnston #include <err.h>
38*e10b9d66SSHENG-YI HONG #include <pthread.h>
39d1c5d0cfSMark Johnston #include <stdbool.h>
40d1c5d0cfSMark Johnston #include <stdlib.h>
41d1c5d0cfSMark Johnston #include <string.h>
42d1c5d0cfSMark Johnston #include <sysexits.h>
43d1c5d0cfSMark Johnston #include <termios.h>
44d1c5d0cfSMark Johnston #include <unistd.h>
45d1c5d0cfSMark Johnston 
46d1c5d0cfSMark Johnston #include "debug.h"
47d1c5d0cfSMark Johnston #include "mevent.h"
48d1c5d0cfSMark Johnston #include "uart_backend.h"
49d1c5d0cfSMark Johnston 
50d1c5d0cfSMark Johnston struct ttyfd {
51d1c5d0cfSMark Johnston 	bool	opened;
52d1c5d0cfSMark Johnston 	int	rfd;		/* fd for reading */
53d1c5d0cfSMark Johnston 	int	wfd;		/* fd for writing, may be == rfd */
54d1c5d0cfSMark Johnston };
55d1c5d0cfSMark Johnston 
56d1c5d0cfSMark Johnston #define	FIFOSZ	16
57d1c5d0cfSMark Johnston 
58d1c5d0cfSMark Johnston struct fifo {
59d1c5d0cfSMark Johnston 	uint8_t	buf[FIFOSZ];
60d1c5d0cfSMark Johnston 	int	rindex;		/* index to read from */
61d1c5d0cfSMark Johnston 	int	windex;		/* index to write to */
62d1c5d0cfSMark Johnston 	int	num;		/* number of characters in the fifo */
63d1c5d0cfSMark Johnston 	int	size;		/* size of the fifo */
64d1c5d0cfSMark Johnston };
65d1c5d0cfSMark Johnston 
66d1c5d0cfSMark Johnston struct uart_softc {
67d1c5d0cfSMark Johnston 	struct ttyfd	tty;
68d1c5d0cfSMark Johnston 	struct fifo	rxfifo;
69d1c5d0cfSMark Johnston 	struct mevent	*mev;
70*e10b9d66SSHENG-YI HONG 	pthread_mutex_t mtx;
71d1c5d0cfSMark Johnston };
72d1c5d0cfSMark Johnston 
73d1c5d0cfSMark Johnston static bool uart_stdio;		/* stdio in use for i/o */
74d1c5d0cfSMark Johnston static struct termios tio_stdio_orig;
75d1c5d0cfSMark Johnston 
76d1c5d0cfSMark Johnston static void
ttyclose(void)77d1c5d0cfSMark Johnston ttyclose(void)
78d1c5d0cfSMark Johnston {
79d1c5d0cfSMark Johnston 	tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig);
80d1c5d0cfSMark Johnston }
81d1c5d0cfSMark Johnston 
82d1c5d0cfSMark Johnston static void
ttyopen(struct ttyfd * tf)83d1c5d0cfSMark Johnston ttyopen(struct ttyfd *tf)
84d1c5d0cfSMark Johnston {
85d1c5d0cfSMark Johnston 	struct termios orig, new;
86d1c5d0cfSMark Johnston 
87d1c5d0cfSMark Johnston 	tcgetattr(tf->rfd, &orig);
88d1c5d0cfSMark Johnston 	new = orig;
89d1c5d0cfSMark Johnston 	cfmakeraw(&new);
90d1c5d0cfSMark Johnston 	new.c_cflag |= CLOCAL;
91d1c5d0cfSMark Johnston 	tcsetattr(tf->rfd, TCSANOW, &new);
92d1c5d0cfSMark Johnston 	if (uart_stdio) {
93d1c5d0cfSMark Johnston 		tio_stdio_orig = orig;
94d1c5d0cfSMark Johnston 		atexit(ttyclose);
95d1c5d0cfSMark Johnston 	}
96d1c5d0cfSMark Johnston 	raw_stdio = 1;
97d1c5d0cfSMark Johnston }
98d1c5d0cfSMark Johnston 
99d1c5d0cfSMark Johnston static int
ttyread(struct ttyfd * tf)100d1c5d0cfSMark Johnston ttyread(struct ttyfd *tf)
101d1c5d0cfSMark Johnston {
102d1c5d0cfSMark Johnston 	unsigned char rb;
103d1c5d0cfSMark Johnston 
104d1c5d0cfSMark Johnston 	if (read(tf->rfd, &rb, 1) == 1)
105d1c5d0cfSMark Johnston 		return (rb);
106d1c5d0cfSMark Johnston 	else
107d1c5d0cfSMark Johnston 		return (-1);
108d1c5d0cfSMark Johnston }
109d1c5d0cfSMark Johnston 
110d1c5d0cfSMark Johnston static void
ttywrite(struct ttyfd * tf,unsigned char wb)111d1c5d0cfSMark Johnston ttywrite(struct ttyfd *tf, unsigned char wb)
112d1c5d0cfSMark Johnston {
113d1c5d0cfSMark Johnston 	(void)write(tf->wfd, &wb, 1);
114d1c5d0cfSMark Johnston }
115d1c5d0cfSMark Johnston 
116d1c5d0cfSMark Johnston static bool
rxfifo_available(struct uart_softc * sc)117d1c5d0cfSMark Johnston rxfifo_available(struct uart_softc *sc)
118d1c5d0cfSMark Johnston {
119d1c5d0cfSMark Johnston 	return (sc->rxfifo.num < sc->rxfifo.size);
120d1c5d0cfSMark Johnston }
121d1c5d0cfSMark Johnston 
122d1c5d0cfSMark Johnston int
uart_rxfifo_getchar(struct uart_softc * sc)123d1c5d0cfSMark Johnston uart_rxfifo_getchar(struct uart_softc *sc)
124d1c5d0cfSMark Johnston {
125d1c5d0cfSMark Johnston 	struct fifo *fifo;
126d1c5d0cfSMark Johnston 	int c, error, wasfull;
127d1c5d0cfSMark Johnston 
128d1c5d0cfSMark Johnston 	wasfull = 0;
129d1c5d0cfSMark Johnston 	fifo = &sc->rxfifo;
130d1c5d0cfSMark Johnston 	if (fifo->num > 0) {
131d1c5d0cfSMark Johnston 		if (!rxfifo_available(sc))
132d1c5d0cfSMark Johnston 			wasfull = 1;
133d1c5d0cfSMark Johnston 		c = fifo->buf[fifo->rindex];
134d1c5d0cfSMark Johnston 		fifo->rindex = (fifo->rindex + 1) % fifo->size;
135d1c5d0cfSMark Johnston 		fifo->num--;
136d1c5d0cfSMark Johnston 		if (wasfull) {
137d1c5d0cfSMark Johnston 			if (sc->tty.opened) {
138d1c5d0cfSMark Johnston 				error = mevent_enable(sc->mev);
139d1c5d0cfSMark Johnston 				assert(error == 0);
140d1c5d0cfSMark Johnston 			}
141d1c5d0cfSMark Johnston 		}
142d1c5d0cfSMark Johnston 		return (c);
143d1c5d0cfSMark Johnston 	} else
144d1c5d0cfSMark Johnston 		return (-1);
145d1c5d0cfSMark Johnston }
146d1c5d0cfSMark Johnston 
147d1c5d0cfSMark Johnston int
uart_rxfifo_numchars(struct uart_softc * sc)148d1c5d0cfSMark Johnston uart_rxfifo_numchars(struct uart_softc *sc)
149d1c5d0cfSMark Johnston {
150d1c5d0cfSMark Johnston 	return (sc->rxfifo.num);
151d1c5d0cfSMark Johnston }
152d1c5d0cfSMark Johnston 
153d1c5d0cfSMark Johnston static int
rxfifo_putchar(struct uart_softc * sc,uint8_t ch)154d1c5d0cfSMark Johnston rxfifo_putchar(struct uart_softc *sc, uint8_t ch)
155d1c5d0cfSMark Johnston {
156d1c5d0cfSMark Johnston 	struct fifo *fifo;
157d1c5d0cfSMark Johnston 	int error;
158d1c5d0cfSMark Johnston 
159d1c5d0cfSMark Johnston 	fifo = &sc->rxfifo;
160d1c5d0cfSMark Johnston 
161d1c5d0cfSMark Johnston 	if (fifo->num < fifo->size) {
162d1c5d0cfSMark Johnston 		fifo->buf[fifo->windex] = ch;
163d1c5d0cfSMark Johnston 		fifo->windex = (fifo->windex + 1) % fifo->size;
164d1c5d0cfSMark Johnston 		fifo->num++;
165d1c5d0cfSMark Johnston 		if (!rxfifo_available(sc)) {
166d1c5d0cfSMark Johnston 			if (sc->tty.opened) {
167d1c5d0cfSMark Johnston 				/*
168d1c5d0cfSMark Johnston 				 * Disable mevent callback if the FIFO is full.
169d1c5d0cfSMark Johnston 				 */
170d1c5d0cfSMark Johnston 				error = mevent_disable(sc->mev);
171d1c5d0cfSMark Johnston 				assert(error == 0);
172d1c5d0cfSMark Johnston 			}
173d1c5d0cfSMark Johnston 		}
174d1c5d0cfSMark Johnston 		return (0);
175d1c5d0cfSMark Johnston 	} else
176d1c5d0cfSMark Johnston 		return (-1);
177d1c5d0cfSMark Johnston }
178d1c5d0cfSMark Johnston 
179d1c5d0cfSMark Johnston void
uart_rxfifo_drain(struct uart_softc * sc,bool loopback)180d1c5d0cfSMark Johnston uart_rxfifo_drain(struct uart_softc *sc, bool loopback)
181d1c5d0cfSMark Johnston {
182d1c5d0cfSMark Johnston 	int ch;
183d1c5d0cfSMark Johnston 
184d1c5d0cfSMark Johnston 	if (loopback) {
185d1c5d0cfSMark Johnston 		(void)ttyread(&sc->tty);
186d1c5d0cfSMark Johnston 	} else {
187d1c5d0cfSMark Johnston 		while (rxfifo_available(sc) &&
188d1c5d0cfSMark Johnston 		    ((ch = ttyread(&sc->tty)) != -1))
189d1c5d0cfSMark Johnston 			rxfifo_putchar(sc, ch);
190d1c5d0cfSMark Johnston 	}
191d1c5d0cfSMark Johnston }
192d1c5d0cfSMark Johnston 
193d1c5d0cfSMark Johnston int
uart_rxfifo_putchar(struct uart_softc * sc,uint8_t ch,bool loopback)194d1c5d0cfSMark Johnston uart_rxfifo_putchar(struct uart_softc *sc, uint8_t ch, bool loopback)
195d1c5d0cfSMark Johnston {
196d1c5d0cfSMark Johnston 	if (loopback) {
197d1c5d0cfSMark Johnston 		return (rxfifo_putchar(sc, ch));
198d1c5d0cfSMark Johnston 	} else if (sc->tty.opened) {
199d1c5d0cfSMark Johnston 		ttywrite(&sc->tty, ch);
200d1c5d0cfSMark Johnston 		return (0);
201d1c5d0cfSMark Johnston 	} else {
202d1c5d0cfSMark Johnston 		/* Drop on the floor. */
203d1c5d0cfSMark Johnston 		return (0);
204d1c5d0cfSMark Johnston 	}
205d1c5d0cfSMark Johnston }
206d1c5d0cfSMark Johnston 
207d1c5d0cfSMark Johnston void
uart_rxfifo_reset(struct uart_softc * sc,int size)208d1c5d0cfSMark Johnston uart_rxfifo_reset(struct uart_softc *sc, int size)
209d1c5d0cfSMark Johnston {
210d1c5d0cfSMark Johnston 	char flushbuf[32];
211d1c5d0cfSMark Johnston 	struct fifo *fifo;
212d1c5d0cfSMark Johnston 	ssize_t nread;
213d1c5d0cfSMark Johnston 	int error;
214d1c5d0cfSMark Johnston 
215d1c5d0cfSMark Johnston 	fifo = &sc->rxfifo;
216d1c5d0cfSMark Johnston 	bzero(fifo, sizeof(struct fifo));
217d1c5d0cfSMark Johnston 	fifo->size = size;
218d1c5d0cfSMark Johnston 
219d1c5d0cfSMark Johnston 	if (sc->tty.opened) {
220d1c5d0cfSMark Johnston 		/*
221d1c5d0cfSMark Johnston 		 * Flush any unread input from the tty buffer.
222d1c5d0cfSMark Johnston 		 */
223d1c5d0cfSMark Johnston 		while (1) {
224d1c5d0cfSMark Johnston 			nread = read(sc->tty.rfd, flushbuf, sizeof(flushbuf));
225d1c5d0cfSMark Johnston 			if (nread != sizeof(flushbuf))
226d1c5d0cfSMark Johnston 				break;
227d1c5d0cfSMark Johnston 		}
228d1c5d0cfSMark Johnston 
229d1c5d0cfSMark Johnston 		/*
230d1c5d0cfSMark Johnston 		 * Enable mevent to trigger when new characters are available
231d1c5d0cfSMark Johnston 		 * on the tty fd.
232d1c5d0cfSMark Johnston 		 */
233d1c5d0cfSMark Johnston 		error = mevent_enable(sc->mev);
234d1c5d0cfSMark Johnston 		assert(error == 0);
235d1c5d0cfSMark Johnston 	}
236d1c5d0cfSMark Johnston }
237d1c5d0cfSMark Johnston 
238d1c5d0cfSMark Johnston int
uart_rxfifo_size(struct uart_softc * sc __unused)239d1c5d0cfSMark Johnston uart_rxfifo_size(struct uart_softc *sc __unused)
240d1c5d0cfSMark Johnston {
241d1c5d0cfSMark Johnston 	return (FIFOSZ);
242d1c5d0cfSMark Johnston }
243d1c5d0cfSMark Johnston 
244d1c5d0cfSMark Johnston #ifdef BHYVE_SNAPSHOT
245d1c5d0cfSMark Johnston int
uart_rxfifo_snapshot(struct uart_softc * sc,struct vm_snapshot_meta * meta)246d1c5d0cfSMark Johnston uart_rxfifo_snapshot(struct uart_softc *sc, struct vm_snapshot_meta *meta)
247d1c5d0cfSMark Johnston {
248d1c5d0cfSMark Johnston 	int ret;
249d1c5d0cfSMark Johnston 
250d1c5d0cfSMark Johnston 	SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.rindex, meta, ret, done);
251d1c5d0cfSMark Johnston 	SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.windex, meta, ret, done);
252d1c5d0cfSMark Johnston 	SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.num, meta, ret, done);
253d1c5d0cfSMark Johnston 	SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.size, meta, ret, done);
254d1c5d0cfSMark Johnston 	SNAPSHOT_BUF_OR_LEAVE(sc->rxfifo.buf, sizeof(sc->rxfifo.buf),
255d1c5d0cfSMark Johnston 	    meta, ret, done);
256d1c5d0cfSMark Johnston 
257d1c5d0cfSMark Johnston done:
258d1c5d0cfSMark Johnston 	return (ret);
259d1c5d0cfSMark Johnston }
260d1c5d0cfSMark Johnston #endif
261d1c5d0cfSMark Johnston 
262d1c5d0cfSMark Johnston static int
uart_stdio_backend(struct uart_softc * sc)263d1c5d0cfSMark Johnston uart_stdio_backend(struct uart_softc *sc)
264d1c5d0cfSMark Johnston {
265d1c5d0cfSMark Johnston #ifndef WITHOUT_CAPSICUM
266d1c5d0cfSMark Johnston 	cap_rights_t rights;
267d1c5d0cfSMark Johnston 	cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
268d1c5d0cfSMark Johnston #endif
269d1c5d0cfSMark Johnston 
270d1c5d0cfSMark Johnston 	if (uart_stdio)
271d1c5d0cfSMark Johnston 		return (-1);
272d1c5d0cfSMark Johnston 
273d1c5d0cfSMark Johnston 	sc->tty.rfd = STDIN_FILENO;
274d1c5d0cfSMark Johnston 	sc->tty.wfd = STDOUT_FILENO;
275d1c5d0cfSMark Johnston 	sc->tty.opened = true;
276d1c5d0cfSMark Johnston 
277d1c5d0cfSMark Johnston 	if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0)
278d1c5d0cfSMark Johnston 		return (-1);
279d1c5d0cfSMark Johnston 	if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0)
280d1c5d0cfSMark Johnston 		return (-1);
281d1c5d0cfSMark Johnston 
282d1c5d0cfSMark Johnston #ifndef WITHOUT_CAPSICUM
283d1c5d0cfSMark Johnston 	cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ);
284d1c5d0cfSMark Johnston 	if (caph_rights_limit(sc->tty.rfd, &rights) == -1)
285d1c5d0cfSMark Johnston 		errx(EX_OSERR, "Unable to apply rights for sandbox");
286d1c5d0cfSMark Johnston 	if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1)
287d1c5d0cfSMark Johnston 		errx(EX_OSERR, "Unable to apply rights for sandbox");
288d1c5d0cfSMark Johnston #endif
289d1c5d0cfSMark Johnston 
290d1c5d0cfSMark Johnston 	uart_stdio = true;
291d1c5d0cfSMark Johnston 
292d1c5d0cfSMark Johnston 	return (0);
293d1c5d0cfSMark Johnston }
294d1c5d0cfSMark Johnston 
295d1c5d0cfSMark Johnston static int
uart_tty_backend(struct uart_softc * sc,const char * path)296d1c5d0cfSMark Johnston uart_tty_backend(struct uart_softc *sc, const char *path)
297d1c5d0cfSMark Johnston {
298d1c5d0cfSMark Johnston #ifndef WITHOUT_CAPSICUM
299d1c5d0cfSMark Johnston 	cap_rights_t rights;
300d1c5d0cfSMark Johnston 	cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
301d1c5d0cfSMark Johnston #endif
302d1c5d0cfSMark Johnston 	int fd;
303d1c5d0cfSMark Johnston 
304d1c5d0cfSMark Johnston 	fd = open(path, O_RDWR | O_NONBLOCK);
305d1c5d0cfSMark Johnston 	if (fd < 0)
306d1c5d0cfSMark Johnston 		return (-1);
307d1c5d0cfSMark Johnston 
308d1c5d0cfSMark Johnston 	if (!isatty(fd)) {
309d1c5d0cfSMark Johnston 		close(fd);
310d1c5d0cfSMark Johnston 		return (-1);
311d1c5d0cfSMark Johnston 	}
312d1c5d0cfSMark Johnston 
313d1c5d0cfSMark Johnston 	sc->tty.rfd = sc->tty.wfd = fd;
314d1c5d0cfSMark Johnston 	sc->tty.opened = true;
315d1c5d0cfSMark Johnston 
316d1c5d0cfSMark Johnston #ifndef WITHOUT_CAPSICUM
317d1c5d0cfSMark Johnston 	cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE);
318d1c5d0cfSMark Johnston 	if (caph_rights_limit(fd, &rights) == -1)
319d1c5d0cfSMark Johnston 		errx(EX_OSERR, "Unable to apply rights for sandbox");
320d1c5d0cfSMark Johnston 	if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1)
321d1c5d0cfSMark Johnston 		errx(EX_OSERR, "Unable to apply rights for sandbox");
322d1c5d0cfSMark Johnston #endif
323d1c5d0cfSMark Johnston 
324d1c5d0cfSMark Johnston 	return (0);
325d1c5d0cfSMark Johnston }
326d1c5d0cfSMark Johnston 
327d1c5d0cfSMark Johnston struct uart_softc *
uart_init(void)328d1c5d0cfSMark Johnston uart_init(void)
329d1c5d0cfSMark Johnston {
330*e10b9d66SSHENG-YI HONG 	struct uart_softc *sc = calloc(1, sizeof(struct uart_softc));
331*e10b9d66SSHENG-YI HONG 	if (sc == NULL)
332*e10b9d66SSHENG-YI HONG 		return (NULL);
333*e10b9d66SSHENG-YI HONG 
334*e10b9d66SSHENG-YI HONG 	pthread_mutex_init(&sc->mtx, NULL);
335*e10b9d66SSHENG-YI HONG 
336*e10b9d66SSHENG-YI HONG 	return (sc);
337d1c5d0cfSMark Johnston }
338d1c5d0cfSMark Johnston 
339d1c5d0cfSMark Johnston int
uart_tty_open(struct uart_softc * sc,const char * path,void (* drain)(int,enum ev_type,void *),void * arg)340d1c5d0cfSMark Johnston uart_tty_open(struct uart_softc *sc, const char *path,
341d1c5d0cfSMark Johnston     void (*drain)(int, enum ev_type, void *), void *arg)
342d1c5d0cfSMark Johnston {
343d1c5d0cfSMark Johnston 	int retval;
344d1c5d0cfSMark Johnston 
345d1c5d0cfSMark Johnston 	if (strcmp("stdio", path) == 0)
346d1c5d0cfSMark Johnston 		retval = uart_stdio_backend(sc);
347d1c5d0cfSMark Johnston 	else
348d1c5d0cfSMark Johnston 		retval = uart_tty_backend(sc, path);
349d1c5d0cfSMark Johnston 	if (retval == 0) {
350d1c5d0cfSMark Johnston 		ttyopen(&sc->tty);
351d1c5d0cfSMark Johnston 		sc->mev = mevent_add(sc->tty.rfd, EVF_READ, drain, arg);
352d1c5d0cfSMark Johnston 		assert(sc->mev != NULL);
353d1c5d0cfSMark Johnston 	}
354d1c5d0cfSMark Johnston 
355d1c5d0cfSMark Johnston 	return (retval);
356d1c5d0cfSMark Johnston }
357*e10b9d66SSHENG-YI HONG 
358*e10b9d66SSHENG-YI HONG void
uart_softc_lock(struct uart_softc * sc)359*e10b9d66SSHENG-YI HONG uart_softc_lock(struct uart_softc *sc)
360*e10b9d66SSHENG-YI HONG {
361*e10b9d66SSHENG-YI HONG 	pthread_mutex_lock(&sc->mtx);
362*e10b9d66SSHENG-YI HONG }
363*e10b9d66SSHENG-YI HONG 
364*e10b9d66SSHENG-YI HONG void
uart_softc_unlock(struct uart_softc * sc)365*e10b9d66SSHENG-YI HONG uart_softc_unlock(struct uart_softc *sc)
366*e10b9d66SSHENG-YI HONG {
367*e10b9d66SSHENG-YI HONG 	pthread_mutex_unlock(&sc->mtx);
368*e10b9d66SSHENG-YI HONG }
369