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