xref: /illumos-gate/usr/src/cmd/bhyve/uart_emul.c (revision bf21cd9318e0a3a51b7f02c14a7c1b1aef2dc861)
1*bf21cd93STycho Nightingale /*-
2*bf21cd93STycho Nightingale  * Copyright (c) 2012 NetApp, Inc.
3*bf21cd93STycho Nightingale  * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
4*bf21cd93STycho Nightingale  * All rights reserved.
5*bf21cd93STycho Nightingale  *
6*bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
7*bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
8*bf21cd93STycho Nightingale  * are met:
9*bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
10*bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
11*bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
12*bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
13*bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
14*bf21cd93STycho Nightingale  *
15*bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16*bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
19*bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*bf21cd93STycho Nightingale  * SUCH DAMAGE.
26*bf21cd93STycho Nightingale  *
27*bf21cd93STycho Nightingale  * $FreeBSD: head/usr.sbin/bhyve/uart_emul.c 257293 2013-10-29 00:18:11Z neel $
28*bf21cd93STycho Nightingale  */
29*bf21cd93STycho Nightingale /*
30*bf21cd93STycho Nightingale  * This file and its contents are supplied under the terms of the
31*bf21cd93STycho Nightingale  * Common Development and Distribution License ("CDDL"), version 1.0.
32*bf21cd93STycho Nightingale  * You may only use this file in accordance with the terms of version
33*bf21cd93STycho Nightingale  * 1.0 of the CDDL.
34*bf21cd93STycho Nightingale  *
35*bf21cd93STycho Nightingale  * A full copy of the text of the CDDL should have accompanied this
36*bf21cd93STycho Nightingale  * source.  A copy of the CDDL is also available via the Internet at
37*bf21cd93STycho Nightingale  * http://www.illumos.org/license/CDDL.
38*bf21cd93STycho Nightingale  *
39*bf21cd93STycho Nightingale  * Copyright 2015 Pluribus Networks Inc.
40*bf21cd93STycho Nightingale  */
41*bf21cd93STycho Nightingale 
42*bf21cd93STycho Nightingale #include <sys/cdefs.h>
43*bf21cd93STycho Nightingale __FBSDID("$FreeBSD: head/usr.sbin/bhyve/uart_emul.c 257293 2013-10-29 00:18:11Z neel $");
44*bf21cd93STycho Nightingale 
45*bf21cd93STycho Nightingale #include <sys/types.h>
46*bf21cd93STycho Nightingale #include <dev/ic/ns16550.h>
47*bf21cd93STycho Nightingale 
48*bf21cd93STycho Nightingale #ifndef	__FreeBSD__
49*bf21cd93STycho Nightingale #include <sys/socket.h>
50*bf21cd93STycho Nightingale #include <sys/stat.h>
51*bf21cd93STycho Nightingale #endif
52*bf21cd93STycho Nightingale #include <stdio.h>
53*bf21cd93STycho Nightingale #include <stdlib.h>
54*bf21cd93STycho Nightingale #include <assert.h>
55*bf21cd93STycho Nightingale #include <termios.h>
56*bf21cd93STycho Nightingale #include <unistd.h>
57*bf21cd93STycho Nightingale #include <stdbool.h>
58*bf21cd93STycho Nightingale #include <string.h>
59*bf21cd93STycho Nightingale #include <pthread.h>
60*bf21cd93STycho Nightingale #ifndef	__FreeBSD__
61*bf21cd93STycho Nightingale #include <errno.h>
62*bf21cd93STycho Nightingale #include <fcntl.h>
63*bf21cd93STycho Nightingale #include <poll.h>
64*bf21cd93STycho Nightingale #endif
65*bf21cd93STycho Nightingale 
66*bf21cd93STycho Nightingale #ifndef	__FreeBSD__
67*bf21cd93STycho Nightingale #include <bhyve.h>
68*bf21cd93STycho Nightingale 
69*bf21cd93STycho Nightingale #include "bhyverun.h"
70*bf21cd93STycho Nightingale #endif
71*bf21cd93STycho Nightingale #ifdef	__FreeBSD__
72*bf21cd93STycho Nightingale #include "mevent.h"
73*bf21cd93STycho Nightingale #endif
74*bf21cd93STycho Nightingale #include "uart_emul.h"
75*bf21cd93STycho Nightingale 
76*bf21cd93STycho Nightingale #define	COM1_BASE	0x3F8
77*bf21cd93STycho Nightingale #define	COM1_IRQ	4
78*bf21cd93STycho Nightingale #define	COM2_BASE      	0x2F8
79*bf21cd93STycho Nightingale #define COM2_IRQ	3
80*bf21cd93STycho Nightingale 
81*bf21cd93STycho Nightingale #define	DEFAULT_RCLK	1843200
82*bf21cd93STycho Nightingale #define	DEFAULT_BAUD	9600
83*bf21cd93STycho Nightingale 
84*bf21cd93STycho Nightingale #define	FCR_RX_MASK	0xC0
85*bf21cd93STycho Nightingale 
86*bf21cd93STycho Nightingale #define	MCR_OUT1	0x04
87*bf21cd93STycho Nightingale #define	MCR_OUT2	0x08
88*bf21cd93STycho Nightingale 
89*bf21cd93STycho Nightingale #define	MSR_DELTA_MASK	0x0f
90*bf21cd93STycho Nightingale 
91*bf21cd93STycho Nightingale #ifndef REG_SCR
92*bf21cd93STycho Nightingale #define REG_SCR		com_scr
93*bf21cd93STycho Nightingale #endif
94*bf21cd93STycho Nightingale 
95*bf21cd93STycho Nightingale #define	FIFOSZ	16
96*bf21cd93STycho Nightingale 
97*bf21cd93STycho Nightingale static bool uart_stdio;		/* stdio in use for i/o */
98*bf21cd93STycho Nightingale #ifndef	__FreeBSD__
99*bf21cd93STycho Nightingale static bool uart_bcons;		/* bhyveconsole in use for i/o */
100*bf21cd93STycho Nightingale #endif
101*bf21cd93STycho Nightingale 
102*bf21cd93STycho Nightingale static struct {
103*bf21cd93STycho Nightingale 	int	baseaddr;
104*bf21cd93STycho Nightingale 	int	irq;
105*bf21cd93STycho Nightingale 	bool	inuse;
106*bf21cd93STycho Nightingale } uart_lres[] = {
107*bf21cd93STycho Nightingale 	{ COM1_BASE, COM1_IRQ, false},
108*bf21cd93STycho Nightingale 	{ COM2_BASE, COM2_IRQ, false},
109*bf21cd93STycho Nightingale };
110*bf21cd93STycho Nightingale 
111*bf21cd93STycho Nightingale #define	UART_NLDEVS	(sizeof(uart_lres) / sizeof(uart_lres[0]))
112*bf21cd93STycho Nightingale 
113*bf21cd93STycho Nightingale struct fifo {
114*bf21cd93STycho Nightingale 	uint8_t	buf[FIFOSZ];
115*bf21cd93STycho Nightingale 	int	rindex;		/* index to read from */
116*bf21cd93STycho Nightingale 	int	windex;		/* index to write to */
117*bf21cd93STycho Nightingale 	int	num;		/* number of characters in the fifo */
118*bf21cd93STycho Nightingale 	int	size;		/* size of the fifo */
119*bf21cd93STycho Nightingale };
120*bf21cd93STycho Nightingale 
121*bf21cd93STycho Nightingale struct uart_softc {
122*bf21cd93STycho Nightingale 	pthread_mutex_t mtx;	/* protects all softc elements */
123*bf21cd93STycho Nightingale 	uint8_t data;		/* Data register (R/W) */
124*bf21cd93STycho Nightingale 	uint8_t ier;		/* Interrupt enable register (R/W) */
125*bf21cd93STycho Nightingale 	uint8_t lcr;		/* Line control register (R/W) */
126*bf21cd93STycho Nightingale 	uint8_t mcr;		/* Modem control register (R/W) */
127*bf21cd93STycho Nightingale 	uint8_t lsr;		/* Line status register (R/W) */
128*bf21cd93STycho Nightingale 	uint8_t msr;		/* Modem status register (R/W) */
129*bf21cd93STycho Nightingale 	uint8_t fcr;		/* FIFO control register (W) */
130*bf21cd93STycho Nightingale 	uint8_t scr;		/* Scratch register (R/W) */
131*bf21cd93STycho Nightingale 
132*bf21cd93STycho Nightingale 	uint8_t dll;		/* Baudrate divisor latch LSB */
133*bf21cd93STycho Nightingale 	uint8_t dlh;		/* Baudrate divisor latch MSB */
134*bf21cd93STycho Nightingale 
135*bf21cd93STycho Nightingale 	struct fifo rxfifo;
136*bf21cd93STycho Nightingale 
137*bf21cd93STycho Nightingale 	bool	opened;
138*bf21cd93STycho Nightingale 	bool	stdio;
139*bf21cd93STycho Nightingale #ifndef	__FreeBSD__
140*bf21cd93STycho Nightingale 	bool	bcons;
141*bf21cd93STycho Nightingale 	struct {
142*bf21cd93STycho Nightingale 		pid_t	clipid;
143*bf21cd93STycho Nightingale 		int	clifd;		/* console client unix domain socket */
144*bf21cd93STycho Nightingale 		int	servfd;		/* console server unix domain socket */
145*bf21cd93STycho Nightingale 	} usc_bcons;
146*bf21cd93STycho Nightingale #endif
147*bf21cd93STycho Nightingale 
148*bf21cd93STycho Nightingale 	bool	thre_int_pending;	/* THRE interrupt pending */
149*bf21cd93STycho Nightingale 
150*bf21cd93STycho Nightingale 	void	*arg;
151*bf21cd93STycho Nightingale 	uart_intr_func_t intr_assert;
152*bf21cd93STycho Nightingale 	uart_intr_func_t intr_deassert;
153*bf21cd93STycho Nightingale };
154*bf21cd93STycho Nightingale 
155*bf21cd93STycho Nightingale #ifdef	__FreeBSD__
156*bf21cd93STycho Nightingale static void uart_drain(int fd, enum ev_type ev, void *arg);
157*bf21cd93STycho Nightingale #else
158*bf21cd93STycho Nightingale static void uart_tty_drain(struct uart_softc *sc);
159*bf21cd93STycho Nightingale static int uart_bcons_drain(struct uart_softc *sc);
160*bf21cd93STycho Nightingale #endif
161*bf21cd93STycho Nightingale 
162*bf21cd93STycho Nightingale static struct termios tio_orig, tio_new;	/* I/O Terminals */
163*bf21cd93STycho Nightingale 
164*bf21cd93STycho Nightingale static void
165*bf21cd93STycho Nightingale ttyclose(void)
166*bf21cd93STycho Nightingale {
167*bf21cd93STycho Nightingale 
168*bf21cd93STycho Nightingale 	tcsetattr(STDIN_FILENO, TCSANOW, &tio_orig);
169*bf21cd93STycho Nightingale }
170*bf21cd93STycho Nightingale 
171*bf21cd93STycho Nightingale static void
172*bf21cd93STycho Nightingale ttyopen(void)
173*bf21cd93STycho Nightingale {
174*bf21cd93STycho Nightingale 
175*bf21cd93STycho Nightingale 	tcgetattr(STDIN_FILENO, &tio_orig);
176*bf21cd93STycho Nightingale 
177*bf21cd93STycho Nightingale 	tio_new = tio_orig;
178*bf21cd93STycho Nightingale 	cfmakeraw(&tio_new);
179*bf21cd93STycho Nightingale 	tcsetattr(STDIN_FILENO, TCSANOW, &tio_new);
180*bf21cd93STycho Nightingale 
181*bf21cd93STycho Nightingale 	atexit(ttyclose);
182*bf21cd93STycho Nightingale }
183*bf21cd93STycho Nightingale 
184*bf21cd93STycho Nightingale static bool
185*bf21cd93STycho Nightingale tty_char_available(void)
186*bf21cd93STycho Nightingale {
187*bf21cd93STycho Nightingale 	fd_set rfds;
188*bf21cd93STycho Nightingale 	struct timeval tv;
189*bf21cd93STycho Nightingale 
190*bf21cd93STycho Nightingale 	FD_ZERO(&rfds);
191*bf21cd93STycho Nightingale 	FD_SET(STDIN_FILENO, &rfds);
192*bf21cd93STycho Nightingale 	tv.tv_sec = 0;
193*bf21cd93STycho Nightingale 	tv.tv_usec = 0;
194*bf21cd93STycho Nightingale 	if (select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) > 0 ) {
195*bf21cd93STycho Nightingale 		return (true);
196*bf21cd93STycho Nightingale 	} else {
197*bf21cd93STycho Nightingale 		return (false);
198*bf21cd93STycho Nightingale 	}
199*bf21cd93STycho Nightingale }
200*bf21cd93STycho Nightingale 
201*bf21cd93STycho Nightingale static int
202*bf21cd93STycho Nightingale ttyread(void)
203*bf21cd93STycho Nightingale {
204*bf21cd93STycho Nightingale 	char rb;
205*bf21cd93STycho Nightingale 
206*bf21cd93STycho Nightingale 	if (tty_char_available()) {
207*bf21cd93STycho Nightingale 		read(STDIN_FILENO, &rb, 1);
208*bf21cd93STycho Nightingale 		return (rb & 0xff);
209*bf21cd93STycho Nightingale 	} else {
210*bf21cd93STycho Nightingale 		return (-1);
211*bf21cd93STycho Nightingale 	}
212*bf21cd93STycho Nightingale }
213*bf21cd93STycho Nightingale 
214*bf21cd93STycho Nightingale static void
215*bf21cd93STycho Nightingale ttywrite(unsigned char wb)
216*bf21cd93STycho Nightingale {
217*bf21cd93STycho Nightingale 
218*bf21cd93STycho Nightingale 	(void)write(STDIN_FILENO, &wb, 1);
219*bf21cd93STycho Nightingale }
220*bf21cd93STycho Nightingale 
221*bf21cd93STycho Nightingale #ifndef	__FreeBSD__
222*bf21cd93STycho Nightingale static void
223*bf21cd93STycho Nightingale bconswrite(struct uart_softc *sc, unsigned char wb)
224*bf21cd93STycho Nightingale {
225*bf21cd93STycho Nightingale 	(void) write(sc->usc_bcons.clifd, &wb, 1);
226*bf21cd93STycho Nightingale }
227*bf21cd93STycho Nightingale #endif
228*bf21cd93STycho Nightingale 
229*bf21cd93STycho Nightingale static void
230*bf21cd93STycho Nightingale fifo_reset(struct fifo *fifo, int size)
231*bf21cd93STycho Nightingale {
232*bf21cd93STycho Nightingale 	bzero(fifo, sizeof(struct fifo));
233*bf21cd93STycho Nightingale 	fifo->size = size;
234*bf21cd93STycho Nightingale }
235*bf21cd93STycho Nightingale 
236*bf21cd93STycho Nightingale static int
237*bf21cd93STycho Nightingale fifo_putchar(struct fifo *fifo, uint8_t ch)
238*bf21cd93STycho Nightingale {
239*bf21cd93STycho Nightingale 
240*bf21cd93STycho Nightingale 	if (fifo->num < fifo->size) {
241*bf21cd93STycho Nightingale 		fifo->buf[fifo->windex] = ch;
242*bf21cd93STycho Nightingale 		fifo->windex = (fifo->windex + 1) % fifo->size;
243*bf21cd93STycho Nightingale 		fifo->num++;
244*bf21cd93STycho Nightingale 		return (0);
245*bf21cd93STycho Nightingale 	} else
246*bf21cd93STycho Nightingale 		return (-1);
247*bf21cd93STycho Nightingale }
248*bf21cd93STycho Nightingale 
249*bf21cd93STycho Nightingale static int
250*bf21cd93STycho Nightingale fifo_getchar(struct fifo *fifo)
251*bf21cd93STycho Nightingale {
252*bf21cd93STycho Nightingale 	int c;
253*bf21cd93STycho Nightingale 
254*bf21cd93STycho Nightingale 	if (fifo->num > 0) {
255*bf21cd93STycho Nightingale 		c = fifo->buf[fifo->rindex];
256*bf21cd93STycho Nightingale 		fifo->rindex = (fifo->rindex + 1) % fifo->size;
257*bf21cd93STycho Nightingale 		fifo->num--;
258*bf21cd93STycho Nightingale 		return (c);
259*bf21cd93STycho Nightingale 	} else
260*bf21cd93STycho Nightingale 		return (-1);
261*bf21cd93STycho Nightingale }
262*bf21cd93STycho Nightingale 
263*bf21cd93STycho Nightingale static int
264*bf21cd93STycho Nightingale fifo_numchars(struct fifo *fifo)
265*bf21cd93STycho Nightingale {
266*bf21cd93STycho Nightingale 
267*bf21cd93STycho Nightingale 	return (fifo->num);
268*bf21cd93STycho Nightingale }
269*bf21cd93STycho Nightingale 
270*bf21cd93STycho Nightingale static int
271*bf21cd93STycho Nightingale fifo_available(struct fifo *fifo)
272*bf21cd93STycho Nightingale {
273*bf21cd93STycho Nightingale 
274*bf21cd93STycho Nightingale 	return (fifo->num < fifo->size);
275*bf21cd93STycho Nightingale }
276*bf21cd93STycho Nightingale 
277*bf21cd93STycho Nightingale static void
278*bf21cd93STycho Nightingale uart_opentty(struct uart_softc *sc)
279*bf21cd93STycho Nightingale {
280*bf21cd93STycho Nightingale 	struct mevent *mev;
281*bf21cd93STycho Nightingale 
282*bf21cd93STycho Nightingale 	assert(!sc->opened && sc->stdio);
283*bf21cd93STycho Nightingale 
284*bf21cd93STycho Nightingale 	ttyopen();
285*bf21cd93STycho Nightingale #ifdef	__FreeBSD__
286*bf21cd93STycho Nightingale 	mev = mevent_add(STDIN_FILENO, EVF_READ, uart_drain, sc);
287*bf21cd93STycho Nightingale #endif
288*bf21cd93STycho Nightingale 	assert(mev);
289*bf21cd93STycho Nightingale }
290*bf21cd93STycho Nightingale 
291*bf21cd93STycho Nightingale /*
292*bf21cd93STycho Nightingale  * The IIR returns a prioritized interrupt reason:
293*bf21cd93STycho Nightingale  * - receive data available
294*bf21cd93STycho Nightingale  * - transmit holding register empty
295*bf21cd93STycho Nightingale  * - modem status change
296*bf21cd93STycho Nightingale  *
297*bf21cd93STycho Nightingale  * Return an interrupt reason if one is available.
298*bf21cd93STycho Nightingale  */
299*bf21cd93STycho Nightingale static int
300*bf21cd93STycho Nightingale uart_intr_reason(struct uart_softc *sc)
301*bf21cd93STycho Nightingale {
302*bf21cd93STycho Nightingale 
303*bf21cd93STycho Nightingale 	if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)
304*bf21cd93STycho Nightingale 		return (IIR_RLS);
305*bf21cd93STycho Nightingale 	else if (fifo_numchars(&sc->rxfifo) > 0 && (sc->ier & IER_ERXRDY) != 0)
306*bf21cd93STycho Nightingale 		return (IIR_RXTOUT);
307*bf21cd93STycho Nightingale 	else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)
308*bf21cd93STycho Nightingale 		return (IIR_TXRDY);
309*bf21cd93STycho Nightingale 	else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0)
310*bf21cd93STycho Nightingale 		return (IIR_MLSC);
311*bf21cd93STycho Nightingale 	else
312*bf21cd93STycho Nightingale 		return (IIR_NOPEND);
313*bf21cd93STycho Nightingale }
314*bf21cd93STycho Nightingale 
315*bf21cd93STycho Nightingale static void
316*bf21cd93STycho Nightingale uart_reset(struct uart_softc *sc)
317*bf21cd93STycho Nightingale {
318*bf21cd93STycho Nightingale 	uint16_t divisor;
319*bf21cd93STycho Nightingale 
320*bf21cd93STycho Nightingale 	divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16;
321*bf21cd93STycho Nightingale 	sc->dll = divisor;
322*bf21cd93STycho Nightingale 	sc->dlh = divisor >> 16;
323*bf21cd93STycho Nightingale 
324*bf21cd93STycho Nightingale 	fifo_reset(&sc->rxfifo, 1);	/* no fifo until enabled by software */
325*bf21cd93STycho Nightingale }
326*bf21cd93STycho Nightingale 
327*bf21cd93STycho Nightingale /*
328*bf21cd93STycho Nightingale  * Toggle the COM port's intr pin depending on whether or not we have an
329*bf21cd93STycho Nightingale  * interrupt condition to report to the processor.
330*bf21cd93STycho Nightingale  */
331*bf21cd93STycho Nightingale static void
332*bf21cd93STycho Nightingale uart_toggle_intr(struct uart_softc *sc)
333*bf21cd93STycho Nightingale {
334*bf21cd93STycho Nightingale 	uint8_t intr_reason;
335*bf21cd93STycho Nightingale 
336*bf21cd93STycho Nightingale 	intr_reason = uart_intr_reason(sc);
337*bf21cd93STycho Nightingale 
338*bf21cd93STycho Nightingale 	if (intr_reason == IIR_NOPEND)
339*bf21cd93STycho Nightingale 		(*sc->intr_deassert)(sc->arg);
340*bf21cd93STycho Nightingale 	else
341*bf21cd93STycho Nightingale 		(*sc->intr_assert)(sc->arg);
342*bf21cd93STycho Nightingale }
343*bf21cd93STycho Nightingale 
344*bf21cd93STycho Nightingale #ifdef	__FreeBSD__
345*bf21cd93STycho Nightingale static void
346*bf21cd93STycho Nightingale uart_drain(int fd, enum ev_type ev, void *arg)
347*bf21cd93STycho Nightingale {
348*bf21cd93STycho Nightingale 	struct uart_softc *sc;
349*bf21cd93STycho Nightingale 	int ch;
350*bf21cd93STycho Nightingale 
351*bf21cd93STycho Nightingale 	sc = arg;
352*bf21cd93STycho Nightingale 
353*bf21cd93STycho Nightingale 	assert(fd == STDIN_FILENO);
354*bf21cd93STycho Nightingale 	assert(ev == EVF_READ);
355*bf21cd93STycho Nightingale 
356*bf21cd93STycho Nightingale 	/*
357*bf21cd93STycho Nightingale 	 * This routine is called in the context of the mevent thread
358*bf21cd93STycho Nightingale 	 * to take out the softc lock to protect against concurrent
359*bf21cd93STycho Nightingale 	 * access from a vCPU i/o exit
360*bf21cd93STycho Nightingale 	 */
361*bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
362*bf21cd93STycho Nightingale 
363*bf21cd93STycho Nightingale 	if ((sc->mcr & MCR_LOOPBACK) != 0) {
364*bf21cd93STycho Nightingale 		(void) ttyread();
365*bf21cd93STycho Nightingale 	} else {
366*bf21cd93STycho Nightingale 		while (fifo_available(&sc->rxfifo) &&
367*bf21cd93STycho Nightingale 		       ((ch = ttyread()) != -1)) {
368*bf21cd93STycho Nightingale 			fifo_putchar(&sc->rxfifo, ch);
369*bf21cd93STycho Nightingale 		}
370*bf21cd93STycho Nightingale 		uart_toggle_intr(sc);
371*bf21cd93STycho Nightingale 	}
372*bf21cd93STycho Nightingale 
373*bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
374*bf21cd93STycho Nightingale }
375*bf21cd93STycho Nightingale #else
376*bf21cd93STycho Nightingale static void
377*bf21cd93STycho Nightingale uart_tty_drain(struct uart_softc *sc)
378*bf21cd93STycho Nightingale {
379*bf21cd93STycho Nightingale 	int ch;
380*bf21cd93STycho Nightingale 
381*bf21cd93STycho Nightingale 	/*
382*bf21cd93STycho Nightingale 	 * Take the softc lock to protect against concurrent
383*bf21cd93STycho Nightingale 	 * access from a vCPU i/o exit
384*bf21cd93STycho Nightingale 	 */
385*bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
386*bf21cd93STycho Nightingale 
387*bf21cd93STycho Nightingale 	if ((sc->mcr & MCR_LOOPBACK) != 0) {
388*bf21cd93STycho Nightingale 		(void) ttyread();
389*bf21cd93STycho Nightingale 	} else {
390*bf21cd93STycho Nightingale 		while (fifo_available(&sc->rxfifo) &&
391*bf21cd93STycho Nightingale 		       ((ch = ttyread()) != -1)) {
392*bf21cd93STycho Nightingale 			fifo_putchar(&sc->rxfifo, ch);
393*bf21cd93STycho Nightingale 		}
394*bf21cd93STycho Nightingale 		uart_toggle_intr(sc);
395*bf21cd93STycho Nightingale 	}
396*bf21cd93STycho Nightingale 
397*bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
398*bf21cd93STycho Nightingale }
399*bf21cd93STycho Nightingale 
400*bf21cd93STycho Nightingale static int
401*bf21cd93STycho Nightingale uart_bcons_drain(struct uart_softc *sc)
402*bf21cd93STycho Nightingale {
403*bf21cd93STycho Nightingale 	char ch;
404*bf21cd93STycho Nightingale 	int nbytes;
405*bf21cd93STycho Nightingale 	int ret = 0;
406*bf21cd93STycho Nightingale 
407*bf21cd93STycho Nightingale 	/*
408*bf21cd93STycho Nightingale 	 * Take the softc lock to protect against concurrent
409*bf21cd93STycho Nightingale 	 * access from a vCPU i/o exit
410*bf21cd93STycho Nightingale 	 */
411*bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
412*bf21cd93STycho Nightingale 
413*bf21cd93STycho Nightingale 	if ((sc->mcr & MCR_LOOPBACK) != 0) {
414*bf21cd93STycho Nightingale 		(void) read(sc->usc_bcons.clifd, &ch, 1);
415*bf21cd93STycho Nightingale 	} else {
416*bf21cd93STycho Nightingale 		for (;;) {
417*bf21cd93STycho Nightingale 			nbytes = read(sc->usc_bcons.clifd, &ch, 1);
418*bf21cd93STycho Nightingale 			if (nbytes == 0) {
419*bf21cd93STycho Nightingale 				ret = 1;
420*bf21cd93STycho Nightingale 				break;
421*bf21cd93STycho Nightingale 			}
422*bf21cd93STycho Nightingale 			if (nbytes == -1 &&
423*bf21cd93STycho Nightingale 			    errno != EINTR && errno != EAGAIN) {
424*bf21cd93STycho Nightingale 				ret = -1;
425*bf21cd93STycho Nightingale 				break;
426*bf21cd93STycho Nightingale 			}
427*bf21cd93STycho Nightingale 			if (nbytes == -1) {
428*bf21cd93STycho Nightingale 				break;
429*bf21cd93STycho Nightingale 			}
430*bf21cd93STycho Nightingale 
431*bf21cd93STycho Nightingale 			if (fifo_available(&sc->rxfifo)) {
432*bf21cd93STycho Nightingale 				fifo_putchar(&sc->rxfifo, ch);
433*bf21cd93STycho Nightingale 			}
434*bf21cd93STycho Nightingale 		}
435*bf21cd93STycho Nightingale 		uart_toggle_intr(sc);
436*bf21cd93STycho Nightingale 	}
437*bf21cd93STycho Nightingale 
438*bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
439*bf21cd93STycho Nightingale 
440*bf21cd93STycho Nightingale 	return (ret);
441*bf21cd93STycho Nightingale }
442*bf21cd93STycho Nightingale #endif
443*bf21cd93STycho Nightingale 
444*bf21cd93STycho Nightingale void
445*bf21cd93STycho Nightingale uart_write(struct uart_softc *sc, int offset, uint8_t value)
446*bf21cd93STycho Nightingale {
447*bf21cd93STycho Nightingale 	int fifosz;
448*bf21cd93STycho Nightingale 	uint8_t msr;
449*bf21cd93STycho Nightingale 
450*bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
451*bf21cd93STycho Nightingale 
452*bf21cd93STycho Nightingale 	/* Open terminal */
453*bf21cd93STycho Nightingale 	if (!sc->opened && sc->stdio) {
454*bf21cd93STycho Nightingale 		uart_opentty(sc);
455*bf21cd93STycho Nightingale 		sc->opened = true;
456*bf21cd93STycho Nightingale 	}
457*bf21cd93STycho Nightingale 
458*bf21cd93STycho Nightingale 	/*
459*bf21cd93STycho Nightingale 	 * Take care of the special case DLAB accesses first
460*bf21cd93STycho Nightingale 	 */
461*bf21cd93STycho Nightingale 	if ((sc->lcr & LCR_DLAB) != 0) {
462*bf21cd93STycho Nightingale 		if (offset == REG_DLL) {
463*bf21cd93STycho Nightingale 			sc->dll = value;
464*bf21cd93STycho Nightingale 			goto done;
465*bf21cd93STycho Nightingale 		}
466*bf21cd93STycho Nightingale 
467*bf21cd93STycho Nightingale 		if (offset == REG_DLH) {
468*bf21cd93STycho Nightingale 			sc->dlh = value;
469*bf21cd93STycho Nightingale 			goto done;
470*bf21cd93STycho Nightingale 		}
471*bf21cd93STycho Nightingale 	}
472*bf21cd93STycho Nightingale 
473*bf21cd93STycho Nightingale         switch (offset) {
474*bf21cd93STycho Nightingale 	case REG_DATA:
475*bf21cd93STycho Nightingale 		if (sc->mcr & MCR_LOOPBACK) {
476*bf21cd93STycho Nightingale 			if (fifo_putchar(&sc->rxfifo, value) != 0)
477*bf21cd93STycho Nightingale 				sc->lsr |= LSR_OE;
478*bf21cd93STycho Nightingale 		} else if (sc->stdio) {
479*bf21cd93STycho Nightingale 			ttywrite(value);
480*bf21cd93STycho Nightingale #ifndef	__FreeBSD__
481*bf21cd93STycho Nightingale 		} else if (sc->bcons) {
482*bf21cd93STycho Nightingale 				bconswrite(sc, value);
483*bf21cd93STycho Nightingale #endif
484*bf21cd93STycho Nightingale 		} /* else drop on floor */
485*bf21cd93STycho Nightingale 		sc->thre_int_pending = true;
486*bf21cd93STycho Nightingale 		break;
487*bf21cd93STycho Nightingale 	case REG_IER:
488*bf21cd93STycho Nightingale 		/*
489*bf21cd93STycho Nightingale 		 * Apply mask so that bits 4-7 are 0
490*bf21cd93STycho Nightingale 		 * Also enables bits 0-3 only if they're 1
491*bf21cd93STycho Nightingale 		 */
492*bf21cd93STycho Nightingale 		sc->ier = value & 0x0F;
493*bf21cd93STycho Nightingale 		break;
494*bf21cd93STycho Nightingale 		case REG_FCR:
495*bf21cd93STycho Nightingale 			/*
496*bf21cd93STycho Nightingale 			 * When moving from FIFO and 16450 mode and vice versa,
497*bf21cd93STycho Nightingale 			 * the FIFO contents are reset.
498*bf21cd93STycho Nightingale 			 */
499*bf21cd93STycho Nightingale 			if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
500*bf21cd93STycho Nightingale 				fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;
501*bf21cd93STycho Nightingale 				fifo_reset(&sc->rxfifo, fifosz);
502*bf21cd93STycho Nightingale 			}
503*bf21cd93STycho Nightingale 
504*bf21cd93STycho Nightingale 			/*
505*bf21cd93STycho Nightingale 			 * The FCR_ENABLE bit must be '1' for the programming
506*bf21cd93STycho Nightingale 			 * of other FCR bits to be effective.
507*bf21cd93STycho Nightingale 			 */
508*bf21cd93STycho Nightingale 			if ((value & FCR_ENABLE) == 0) {
509*bf21cd93STycho Nightingale 				sc->fcr = 0;
510*bf21cd93STycho Nightingale 			} else {
511*bf21cd93STycho Nightingale 				if ((value & FCR_RCV_RST) != 0)
512*bf21cd93STycho Nightingale 					fifo_reset(&sc->rxfifo, FIFOSZ);
513*bf21cd93STycho Nightingale 
514*bf21cd93STycho Nightingale 				sc->fcr = value &
515*bf21cd93STycho Nightingale 					 (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
516*bf21cd93STycho Nightingale 			}
517*bf21cd93STycho Nightingale 			break;
518*bf21cd93STycho Nightingale 		case REG_LCR:
519*bf21cd93STycho Nightingale 			sc->lcr = value;
520*bf21cd93STycho Nightingale 			break;
521*bf21cd93STycho Nightingale 		case REG_MCR:
522*bf21cd93STycho Nightingale 			/* Apply mask so that bits 5-7 are 0 */
523*bf21cd93STycho Nightingale 			sc->mcr = value & 0x1F;
524*bf21cd93STycho Nightingale 
525*bf21cd93STycho Nightingale 			msr = 0;
526*bf21cd93STycho Nightingale 			if (sc->mcr & MCR_LOOPBACK) {
527*bf21cd93STycho Nightingale 				/*
528*bf21cd93STycho Nightingale 				 * In the loopback mode certain bits from the
529*bf21cd93STycho Nightingale 				 * MCR are reflected back into MSR
530*bf21cd93STycho Nightingale 				 */
531*bf21cd93STycho Nightingale 				if (sc->mcr & MCR_RTS)
532*bf21cd93STycho Nightingale 					msr |= MSR_CTS;
533*bf21cd93STycho Nightingale 				if (sc->mcr & MCR_DTR)
534*bf21cd93STycho Nightingale 					msr |= MSR_DSR;
535*bf21cd93STycho Nightingale 				if (sc->mcr & MCR_OUT1)
536*bf21cd93STycho Nightingale 					msr |= MSR_RI;
537*bf21cd93STycho Nightingale 				if (sc->mcr & MCR_OUT2)
538*bf21cd93STycho Nightingale 					msr |= MSR_DCD;
539*bf21cd93STycho Nightingale 			}
540*bf21cd93STycho Nightingale 
541*bf21cd93STycho Nightingale 			/*
542*bf21cd93STycho Nightingale 			 * Detect if there has been any change between the
543*bf21cd93STycho Nightingale 			 * previous and the new value of MSR. If there is
544*bf21cd93STycho Nightingale 			 * then assert the appropriate MSR delta bit.
545*bf21cd93STycho Nightingale 			 */
546*bf21cd93STycho Nightingale 			if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))
547*bf21cd93STycho Nightingale 				sc->msr |= MSR_DCTS;
548*bf21cd93STycho Nightingale 			if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))
549*bf21cd93STycho Nightingale 				sc->msr |= MSR_DDSR;
550*bf21cd93STycho Nightingale 			if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))
551*bf21cd93STycho Nightingale 				sc->msr |= MSR_DDCD;
552*bf21cd93STycho Nightingale 			if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
553*bf21cd93STycho Nightingale 				sc->msr |= MSR_TERI;
554*bf21cd93STycho Nightingale 
555*bf21cd93STycho Nightingale 			/*
556*bf21cd93STycho Nightingale 			 * Update the value of MSR while retaining the delta
557*bf21cd93STycho Nightingale 			 * bits.
558*bf21cd93STycho Nightingale 			 */
559*bf21cd93STycho Nightingale 			sc->msr &= MSR_DELTA_MASK;
560*bf21cd93STycho Nightingale 			sc->msr |= msr;
561*bf21cd93STycho Nightingale 			break;
562*bf21cd93STycho Nightingale 		case REG_LSR:
563*bf21cd93STycho Nightingale 			/*
564*bf21cd93STycho Nightingale 			 * Line status register is not meant to be written to
565*bf21cd93STycho Nightingale 			 * during normal operation.
566*bf21cd93STycho Nightingale 			 */
567*bf21cd93STycho Nightingale 			break;
568*bf21cd93STycho Nightingale 		case REG_MSR:
569*bf21cd93STycho Nightingale 			/*
570*bf21cd93STycho Nightingale 			 * As far as I can tell MSR is a read-only register.
571*bf21cd93STycho Nightingale 			 */
572*bf21cd93STycho Nightingale 			break;
573*bf21cd93STycho Nightingale 		case REG_SCR:
574*bf21cd93STycho Nightingale 			sc->scr = value;
575*bf21cd93STycho Nightingale 			break;
576*bf21cd93STycho Nightingale 		default:
577*bf21cd93STycho Nightingale 			break;
578*bf21cd93STycho Nightingale 	}
579*bf21cd93STycho Nightingale 
580*bf21cd93STycho Nightingale done:
581*bf21cd93STycho Nightingale 	uart_toggle_intr(sc);
582*bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
583*bf21cd93STycho Nightingale }
584*bf21cd93STycho Nightingale 
585*bf21cd93STycho Nightingale uint8_t
586*bf21cd93STycho Nightingale uart_read(struct uart_softc *sc, int offset)
587*bf21cd93STycho Nightingale {
588*bf21cd93STycho Nightingale 	uint8_t iir, intr_reason, reg;
589*bf21cd93STycho Nightingale 
590*bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
591*bf21cd93STycho Nightingale 
592*bf21cd93STycho Nightingale 	/* Open terminal */
593*bf21cd93STycho Nightingale 	if (!sc->opened && sc->stdio) {
594*bf21cd93STycho Nightingale 		uart_opentty(sc);
595*bf21cd93STycho Nightingale 		sc->opened = true;
596*bf21cd93STycho Nightingale 	}
597*bf21cd93STycho Nightingale 
598*bf21cd93STycho Nightingale 	/*
599*bf21cd93STycho Nightingale 	 * Take care of the special case DLAB accesses first
600*bf21cd93STycho Nightingale 	 */
601*bf21cd93STycho Nightingale 	if ((sc->lcr & LCR_DLAB) != 0) {
602*bf21cd93STycho Nightingale 		if (offset == REG_DLL) {
603*bf21cd93STycho Nightingale 			reg = sc->dll;
604*bf21cd93STycho Nightingale 			goto done;
605*bf21cd93STycho Nightingale 		}
606*bf21cd93STycho Nightingale 
607*bf21cd93STycho Nightingale 		if (offset == REG_DLH) {
608*bf21cd93STycho Nightingale 			reg = sc->dlh;
609*bf21cd93STycho Nightingale 			goto done;
610*bf21cd93STycho Nightingale 		}
611*bf21cd93STycho Nightingale 	}
612*bf21cd93STycho Nightingale 
613*bf21cd93STycho Nightingale 	switch (offset) {
614*bf21cd93STycho Nightingale 	case REG_DATA:
615*bf21cd93STycho Nightingale 		reg = fifo_getchar(&sc->rxfifo);
616*bf21cd93STycho Nightingale 		break;
617*bf21cd93STycho Nightingale 	case REG_IER:
618*bf21cd93STycho Nightingale 		reg = sc->ier;
619*bf21cd93STycho Nightingale 		break;
620*bf21cd93STycho Nightingale 	case REG_IIR:
621*bf21cd93STycho Nightingale 		iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
622*bf21cd93STycho Nightingale 
623*bf21cd93STycho Nightingale 		intr_reason = uart_intr_reason(sc);
624*bf21cd93STycho Nightingale 
625*bf21cd93STycho Nightingale 		/*
626*bf21cd93STycho Nightingale 		 * Deal with side effects of reading the IIR register
627*bf21cd93STycho Nightingale 		 */
628*bf21cd93STycho Nightingale 		if (intr_reason == IIR_TXRDY)
629*bf21cd93STycho Nightingale 			sc->thre_int_pending = false;
630*bf21cd93STycho Nightingale 
631*bf21cd93STycho Nightingale 		iir |= intr_reason;
632*bf21cd93STycho Nightingale 
633*bf21cd93STycho Nightingale 		reg = iir;
634*bf21cd93STycho Nightingale 		break;
635*bf21cd93STycho Nightingale 	case REG_LCR:
636*bf21cd93STycho Nightingale 		reg = sc->lcr;
637*bf21cd93STycho Nightingale 		break;
638*bf21cd93STycho Nightingale 	case REG_MCR:
639*bf21cd93STycho Nightingale 		reg = sc->mcr;
640*bf21cd93STycho Nightingale 		break;
641*bf21cd93STycho Nightingale 	case REG_LSR:
642*bf21cd93STycho Nightingale 		/* Transmitter is always ready for more data */
643*bf21cd93STycho Nightingale 		sc->lsr |= LSR_TEMT | LSR_THRE;
644*bf21cd93STycho Nightingale 
645*bf21cd93STycho Nightingale 		/* Check for new receive data */
646*bf21cd93STycho Nightingale 		if (fifo_numchars(&sc->rxfifo) > 0)
647*bf21cd93STycho Nightingale 			sc->lsr |= LSR_RXRDY;
648*bf21cd93STycho Nightingale 		else
649*bf21cd93STycho Nightingale 			sc->lsr &= ~LSR_RXRDY;
650*bf21cd93STycho Nightingale 
651*bf21cd93STycho Nightingale 		reg = sc->lsr;
652*bf21cd93STycho Nightingale 
653*bf21cd93STycho Nightingale 		/* The LSR_OE bit is cleared on LSR read */
654*bf21cd93STycho Nightingale 		sc->lsr &= ~LSR_OE;
655*bf21cd93STycho Nightingale 		break;
656*bf21cd93STycho Nightingale 	case REG_MSR:
657*bf21cd93STycho Nightingale 		/*
658*bf21cd93STycho Nightingale 		 * MSR delta bits are cleared on read
659*bf21cd93STycho Nightingale 		 */
660*bf21cd93STycho Nightingale 		reg = sc->msr;
661*bf21cd93STycho Nightingale 		sc->msr &= ~MSR_DELTA_MASK;
662*bf21cd93STycho Nightingale 		break;
663*bf21cd93STycho Nightingale 	case REG_SCR:
664*bf21cd93STycho Nightingale 		reg = sc->scr;
665*bf21cd93STycho Nightingale 		break;
666*bf21cd93STycho Nightingale 	default:
667*bf21cd93STycho Nightingale 		reg = 0xFF;
668*bf21cd93STycho Nightingale 		break;
669*bf21cd93STycho Nightingale 	}
670*bf21cd93STycho Nightingale 
671*bf21cd93STycho Nightingale done:
672*bf21cd93STycho Nightingale 	uart_toggle_intr(sc);
673*bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
674*bf21cd93STycho Nightingale 
675*bf21cd93STycho Nightingale 	return (reg);
676*bf21cd93STycho Nightingale }
677*bf21cd93STycho Nightingale 
678*bf21cd93STycho Nightingale #ifndef	__FreeBSD__
679*bf21cd93STycho Nightingale static void *
680*bf21cd93STycho Nightingale uart_tty_thread(void *param)
681*bf21cd93STycho Nightingale {
682*bf21cd93STycho Nightingale 	struct uart_softc *sc = param;
683*bf21cd93STycho Nightingale 	pollfd_t pollset;
684*bf21cd93STycho Nightingale 
685*bf21cd93STycho Nightingale 	pollset.fd = STDIN_FILENO;
686*bf21cd93STycho Nightingale 	pollset.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND;
687*bf21cd93STycho Nightingale 
688*bf21cd93STycho Nightingale 	for (;;) {
689*bf21cd93STycho Nightingale 		if (poll(&pollset, 1, -1) < 0) {
690*bf21cd93STycho Nightingale 			if (errno != EINTR) {
691*bf21cd93STycho Nightingale 				perror("poll failed");
692*bf21cd93STycho Nightingale 				break;
693*bf21cd93STycho Nightingale 			}
694*bf21cd93STycho Nightingale 			continue;
695*bf21cd93STycho Nightingale 		}
696*bf21cd93STycho Nightingale 		uart_tty_drain(sc);
697*bf21cd93STycho Nightingale 	}
698*bf21cd93STycho Nightingale 
699*bf21cd93STycho Nightingale 	return (NULL);
700*bf21cd93STycho Nightingale }
701*bf21cd93STycho Nightingale 
702*bf21cd93STycho Nightingale /*
703*bf21cd93STycho Nightingale  * Read the "ident" string from the client's descriptor; this routine also
704*bf21cd93STycho Nightingale  * tolerates being called with pid=NULL, for times when you want to "eat"
705*bf21cd93STycho Nightingale  * the ident string from a client without saving it.
706*bf21cd93STycho Nightingale  */
707*bf21cd93STycho Nightingale static int
708*bf21cd93STycho Nightingale get_client_ident(int clifd, pid_t *pid)
709*bf21cd93STycho Nightingale {
710*bf21cd93STycho Nightingale 	char buf[BUFSIZ], *bufp;
711*bf21cd93STycho Nightingale 	size_t buflen = sizeof (buf);
712*bf21cd93STycho Nightingale 	char c = '\0';
713*bf21cd93STycho Nightingale 	int i = 0, r;
714*bf21cd93STycho Nightingale 
715*bf21cd93STycho Nightingale 	/* "eat up the ident string" case, for simplicity */
716*bf21cd93STycho Nightingale 	if (pid == NULL) {
717*bf21cd93STycho Nightingale 		while (read(clifd, &c, 1) == 1) {
718*bf21cd93STycho Nightingale 			if (c == '\n')
719*bf21cd93STycho Nightingale 				return (0);
720*bf21cd93STycho Nightingale 		}
721*bf21cd93STycho Nightingale 	}
722*bf21cd93STycho Nightingale 
723*bf21cd93STycho Nightingale 	bzero(buf, sizeof (buf));
724*bf21cd93STycho Nightingale 	while ((buflen > 1) && (r = read(clifd, &c, 1)) == 1) {
725*bf21cd93STycho Nightingale 		buflen--;
726*bf21cd93STycho Nightingale 		if (c == '\n')
727*bf21cd93STycho Nightingale 			break;
728*bf21cd93STycho Nightingale 
729*bf21cd93STycho Nightingale 		buf[i] = c;
730*bf21cd93STycho Nightingale 		i++;
731*bf21cd93STycho Nightingale 	}
732*bf21cd93STycho Nightingale 	if (r == -1)
733*bf21cd93STycho Nightingale 		return (-1);
734*bf21cd93STycho Nightingale 
735*bf21cd93STycho Nightingale 	/*
736*bf21cd93STycho Nightingale 	 * We've filled the buffer, but still haven't seen \n.  Keep eating
737*bf21cd93STycho Nightingale 	 * until we find it; we don't expect this to happen, but this is
738*bf21cd93STycho Nightingale 	 * defensive.
739*bf21cd93STycho Nightingale 	 */
740*bf21cd93STycho Nightingale 	if (c != '\n') {
741*bf21cd93STycho Nightingale 		while ((r = read(clifd, &c, sizeof (c))) > 0)
742*bf21cd93STycho Nightingale 			if (c == '\n')
743*bf21cd93STycho Nightingale 				break;
744*bf21cd93STycho Nightingale 	}
745*bf21cd93STycho Nightingale 
746*bf21cd93STycho Nightingale 	/*
747*bf21cd93STycho Nightingale 	 * Parse buffer for message of the form: IDENT <pid>
748*bf21cd93STycho Nightingale 	 */
749*bf21cd93STycho Nightingale 	bufp = buf;
750*bf21cd93STycho Nightingale 	if (strncmp(bufp, "IDENT ", 6) != 0)
751*bf21cd93STycho Nightingale 		return (-1);
752*bf21cd93STycho Nightingale 	bufp += 6;
753*bf21cd93STycho Nightingale 	errno = 0;
754*bf21cd93STycho Nightingale 	*pid = strtoll(bufp, &bufp, 10);
755*bf21cd93STycho Nightingale 	if (errno != 0)
756*bf21cd93STycho Nightingale 		return (-1);
757*bf21cd93STycho Nightingale 
758*bf21cd93STycho Nightingale 	return (0);
759*bf21cd93STycho Nightingale }
760*bf21cd93STycho Nightingale 
761*bf21cd93STycho Nightingale static int
762*bf21cd93STycho Nightingale uart_bcons_accept_client(struct uart_softc *sc)
763*bf21cd93STycho Nightingale {
764*bf21cd93STycho Nightingale 	int connfd;
765*bf21cd93STycho Nightingale 	struct sockaddr_un cliaddr;
766*bf21cd93STycho Nightingale 	socklen_t clilen;
767*bf21cd93STycho Nightingale 	pid_t pid;
768*bf21cd93STycho Nightingale 
769*bf21cd93STycho Nightingale 	clilen = sizeof (cliaddr);
770*bf21cd93STycho Nightingale 	connfd = accept(sc->usc_bcons.servfd,
771*bf21cd93STycho Nightingale 			(struct sockaddr *)&cliaddr, &clilen);
772*bf21cd93STycho Nightingale 	if (connfd == -1)
773*bf21cd93STycho Nightingale 		return (-1);
774*bf21cd93STycho Nightingale 	if (get_client_ident(connfd, &pid) == -1) {
775*bf21cd93STycho Nightingale 		(void) shutdown(connfd, SHUT_RDWR);
776*bf21cd93STycho Nightingale 		(void) close(connfd);
777*bf21cd93STycho Nightingale 		return (-1);
778*bf21cd93STycho Nightingale 	}
779*bf21cd93STycho Nightingale 
780*bf21cd93STycho Nightingale 	if (fcntl(connfd, F_SETFL, O_NONBLOCK) < 0) {
781*bf21cd93STycho Nightingale 		(void) shutdown(connfd, SHUT_RDWR);
782*bf21cd93STycho Nightingale 		(void) close(connfd);
783*bf21cd93STycho Nightingale 		return (-1);
784*bf21cd93STycho Nightingale 	}
785*bf21cd93STycho Nightingale 	(void) write(connfd, "OK\n", 3);
786*bf21cd93STycho Nightingale 
787*bf21cd93STycho Nightingale 	sc->usc_bcons.clipid = pid;
788*bf21cd93STycho Nightingale 	sc->usc_bcons.clifd = connfd;
789*bf21cd93STycho Nightingale 
790*bf21cd93STycho Nightingale 	printf("Connection from process ID %lu.\n", pid);
791*bf21cd93STycho Nightingale 
792*bf21cd93STycho Nightingale 	return (0);
793*bf21cd93STycho Nightingale }
794*bf21cd93STycho Nightingale 
795*bf21cd93STycho Nightingale static void
796*bf21cd93STycho Nightingale uart_bcons_reject_client(struct uart_softc *sc)
797*bf21cd93STycho Nightingale {
798*bf21cd93STycho Nightingale 	int connfd;
799*bf21cd93STycho Nightingale 	struct sockaddr_un cliaddr;
800*bf21cd93STycho Nightingale 	socklen_t clilen;
801*bf21cd93STycho Nightingale 	char nak[MAXPATHLEN];
802*bf21cd93STycho Nightingale 
803*bf21cd93STycho Nightingale 	clilen = sizeof (cliaddr);
804*bf21cd93STycho Nightingale 	connfd = accept(sc->usc_bcons.servfd,
805*bf21cd93STycho Nightingale 			(struct sockaddr *)&cliaddr, &clilen);
806*bf21cd93STycho Nightingale 
807*bf21cd93STycho Nightingale 	/*
808*bf21cd93STycho Nightingale 	 * After hear its ident string, tell client to get lost.
809*bf21cd93STycho Nightingale 	 */
810*bf21cd93STycho Nightingale 	if (get_client_ident(connfd, NULL) == 0) {
811*bf21cd93STycho Nightingale 		(void) snprintf(nak, sizeof (nak), "%lu\n",
812*bf21cd93STycho Nightingale 		    sc->usc_bcons.clipid);
813*bf21cd93STycho Nightingale 		(void) write(connfd, nak, strlen(nak));
814*bf21cd93STycho Nightingale 	}
815*bf21cd93STycho Nightingale 	(void) shutdown(connfd, SHUT_RDWR);
816*bf21cd93STycho Nightingale 	(void) close(connfd);
817*bf21cd93STycho Nightingale }
818*bf21cd93STycho Nightingale 
819*bf21cd93STycho Nightingale static int
820*bf21cd93STycho Nightingale uart_bcons_client_event(struct uart_softc *sc)
821*bf21cd93STycho Nightingale {
822*bf21cd93STycho Nightingale 	int res;
823*bf21cd93STycho Nightingale 
824*bf21cd93STycho Nightingale 	res = uart_bcons_drain(sc);
825*bf21cd93STycho Nightingale 	if (res < 0)
826*bf21cd93STycho Nightingale 		return (-1);
827*bf21cd93STycho Nightingale 
828*bf21cd93STycho Nightingale 	if (res > 0) {
829*bf21cd93STycho Nightingale 		fprintf(stderr, "Closing connection with bhyve console\n");
830*bf21cd93STycho Nightingale 		(void) shutdown(sc->usc_bcons.clifd, SHUT_RDWR);
831*bf21cd93STycho Nightingale 		(void) close(sc->usc_bcons.clifd);
832*bf21cd93STycho Nightingale 		sc->usc_bcons.clifd = -1;
833*bf21cd93STycho Nightingale 	}
834*bf21cd93STycho Nightingale 
835*bf21cd93STycho Nightingale 	return (0);
836*bf21cd93STycho Nightingale }
837*bf21cd93STycho Nightingale 
838*bf21cd93STycho Nightingale static void
839*bf21cd93STycho Nightingale uart_bcons_server_event(struct uart_softc *sc)
840*bf21cd93STycho Nightingale {
841*bf21cd93STycho Nightingale 	int clifd;
842*bf21cd93STycho Nightingale 
843*bf21cd93STycho Nightingale 	if (sc->usc_bcons.clifd != -1) {
844*bf21cd93STycho Nightingale 		/* we're already handling a client */
845*bf21cd93STycho Nightingale 		uart_bcons_reject_client(sc);
846*bf21cd93STycho Nightingale 		return;
847*bf21cd93STycho Nightingale 	}
848*bf21cd93STycho Nightingale 
849*bf21cd93STycho Nightingale 	if (uart_bcons_accept_client(sc) == 0) {
850*bf21cd93STycho Nightingale 		pthread_mutex_lock(&bcons_wait_lock);
851*bf21cd93STycho Nightingale 		bcons_connected = B_TRUE;
852*bf21cd93STycho Nightingale 		pthread_cond_signal(&bcons_wait_done);
853*bf21cd93STycho Nightingale 		pthread_mutex_unlock(&bcons_wait_lock);
854*bf21cd93STycho Nightingale 	}
855*bf21cd93STycho Nightingale }
856*bf21cd93STycho Nightingale 
857*bf21cd93STycho Nightingale static void *
858*bf21cd93STycho Nightingale uart_bcons_thread(void *param)
859*bf21cd93STycho Nightingale {
860*bf21cd93STycho Nightingale 	struct uart_softc *sc = param;
861*bf21cd93STycho Nightingale 	struct pollfd pollfds[2];
862*bf21cd93STycho Nightingale 	int res;
863*bf21cd93STycho Nightingale 
864*bf21cd93STycho Nightingale 	/* read from client and write to vm */
865*bf21cd93STycho Nightingale 	pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND |
866*bf21cd93STycho Nightingale 	    POLLPRI | POLLERR | POLLHUP;
867*bf21cd93STycho Nightingale 
868*bf21cd93STycho Nightingale 	/* the server socket; watch for events (new connections) */
869*bf21cd93STycho Nightingale 	pollfds[1].events = pollfds[0].events;
870*bf21cd93STycho Nightingale 
871*bf21cd93STycho Nightingale 	for (;;) {
872*bf21cd93STycho Nightingale 		pollfds[0].fd = sc->usc_bcons.clifd;
873*bf21cd93STycho Nightingale 		pollfds[1].fd = sc->usc_bcons.servfd;
874*bf21cd93STycho Nightingale 		pollfds[0].revents = pollfds[1].revents = 0;
875*bf21cd93STycho Nightingale 
876*bf21cd93STycho Nightingale 		res = poll(pollfds,
877*bf21cd93STycho Nightingale 		    sizeof (pollfds) / sizeof (struct pollfd), -1);
878*bf21cd93STycho Nightingale 
879*bf21cd93STycho Nightingale 		if (res == -1 && errno != EINTR) {
880*bf21cd93STycho Nightingale 			perror("poll failed");
881*bf21cd93STycho Nightingale 			/* we are hosed, close connection */
882*bf21cd93STycho Nightingale 			break;
883*bf21cd93STycho Nightingale 		}
884*bf21cd93STycho Nightingale 
885*bf21cd93STycho Nightingale 		/* event from client side */
886*bf21cd93STycho Nightingale 		if (pollfds[0].revents) {
887*bf21cd93STycho Nightingale 			if (pollfds[0].revents &
888*bf21cd93STycho Nightingale 			    (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
889*bf21cd93STycho Nightingale 				if (uart_bcons_client_event(sc) < 0)
890*bf21cd93STycho Nightingale 					break;
891*bf21cd93STycho Nightingale 			} else {
892*bf21cd93STycho Nightingale 				break;
893*bf21cd93STycho Nightingale 			}
894*bf21cd93STycho Nightingale 		}
895*bf21cd93STycho Nightingale 
896*bf21cd93STycho Nightingale 		/* event from server socket */
897*bf21cd93STycho Nightingale 		if (pollfds[1].revents) {
898*bf21cd93STycho Nightingale 			if (pollfds[1].revents & (POLLIN | POLLRDNORM)) {
899*bf21cd93STycho Nightingale 				uart_bcons_server_event(sc);
900*bf21cd93STycho Nightingale 			} else {
901*bf21cd93STycho Nightingale 				break;
902*bf21cd93STycho Nightingale 			}
903*bf21cd93STycho Nightingale 		}
904*bf21cd93STycho Nightingale 	}
905*bf21cd93STycho Nightingale 
906*bf21cd93STycho Nightingale 	if (sc->usc_bcons.clifd != -1) {
907*bf21cd93STycho Nightingale 		fprintf(stderr, "Closing connection with bhyve console\n");
908*bf21cd93STycho Nightingale 		(void) shutdown(sc->usc_bcons.clifd, SHUT_RDWR);
909*bf21cd93STycho Nightingale 		(void) close(sc->usc_bcons.clifd);
910*bf21cd93STycho Nightingale 		sc->usc_bcons.clifd = -1;
911*bf21cd93STycho Nightingale 	}
912*bf21cd93STycho Nightingale 
913*bf21cd93STycho Nightingale 	return (NULL);
914*bf21cd93STycho Nightingale }
915*bf21cd93STycho Nightingale 
916*bf21cd93STycho Nightingale static int
917*bf21cd93STycho Nightingale init_bcons_sock(void)
918*bf21cd93STycho Nightingale {
919*bf21cd93STycho Nightingale 	int servfd;
920*bf21cd93STycho Nightingale 	struct sockaddr_un servaddr;
921*bf21cd93STycho Nightingale 
922*bf21cd93STycho Nightingale 	if (mkdir(BHYVE_TMPDIR, S_IRWXU) < 0 && errno != EEXIST) {
923*bf21cd93STycho Nightingale 		fprintf(stderr, "bhyve console setup: "
924*bf21cd93STycho Nightingale 		    "could not mkdir %s", BHYVE_TMPDIR, strerror(errno));
925*bf21cd93STycho Nightingale 		return (-1);
926*bf21cd93STycho Nightingale 	}
927*bf21cd93STycho Nightingale 
928*bf21cd93STycho Nightingale 	bzero(&servaddr, sizeof (servaddr));
929*bf21cd93STycho Nightingale 	servaddr.sun_family = AF_UNIX;
930*bf21cd93STycho Nightingale 	(void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
931*bf21cd93STycho Nightingale 	    BHYVE_CONS_SOCKPATH, vmname);
932*bf21cd93STycho Nightingale 
933*bf21cd93STycho Nightingale 	if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
934*bf21cd93STycho Nightingale 		fprintf(stderr, "bhyve console setup: "
935*bf21cd93STycho Nightingale 		    "could not create socket\n");
936*bf21cd93STycho Nightingale 		return (-1);
937*bf21cd93STycho Nightingale 	}
938*bf21cd93STycho Nightingale 	(void) unlink(servaddr.sun_path);
939*bf21cd93STycho Nightingale 
940*bf21cd93STycho Nightingale 	if (bind(servfd, (struct sockaddr *)&servaddr,
941*bf21cd93STycho Nightingale 	    sizeof (servaddr)) == -1) {
942*bf21cd93STycho Nightingale 		fprintf(stderr, "bhyve console setup: "
943*bf21cd93STycho Nightingale 		    "could not bind to socket\n");
944*bf21cd93STycho Nightingale 		goto out;
945*bf21cd93STycho Nightingale         }
946*bf21cd93STycho Nightingale 
947*bf21cd93STycho Nightingale         if (listen(servfd, 4) == -1) {
948*bf21cd93STycho Nightingale 		fprintf(stderr, "bhyve console setup: "
949*bf21cd93STycho Nightingale 		    "could not listen on socket");
950*bf21cd93STycho Nightingale 		goto out;
951*bf21cd93STycho Nightingale         }
952*bf21cd93STycho Nightingale         return (servfd);
953*bf21cd93STycho Nightingale 
954*bf21cd93STycho Nightingale out:
955*bf21cd93STycho Nightingale 	(void) unlink(servaddr.sun_path);
956*bf21cd93STycho Nightingale         (void) close(servfd);
957*bf21cd93STycho Nightingale         return (-1);
958*bf21cd93STycho Nightingale }
959*bf21cd93STycho Nightingale #endif
960*bf21cd93STycho Nightingale 
961*bf21cd93STycho Nightingale int
962*bf21cd93STycho Nightingale uart_legacy_alloc(int which, int *baseaddr, int *irq)
963*bf21cd93STycho Nightingale {
964*bf21cd93STycho Nightingale 
965*bf21cd93STycho Nightingale 	if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse)
966*bf21cd93STycho Nightingale 		return (-1);
967*bf21cd93STycho Nightingale 
968*bf21cd93STycho Nightingale 	uart_lres[which].inuse = true;
969*bf21cd93STycho Nightingale 	*baseaddr = uart_lres[which].baseaddr;
970*bf21cd93STycho Nightingale 	*irq = uart_lres[which].irq;
971*bf21cd93STycho Nightingale 
972*bf21cd93STycho Nightingale 	return (0);
973*bf21cd93STycho Nightingale }
974*bf21cd93STycho Nightingale 
975*bf21cd93STycho Nightingale struct uart_softc *
976*bf21cd93STycho Nightingale uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
977*bf21cd93STycho Nightingale     void *arg)
978*bf21cd93STycho Nightingale {
979*bf21cd93STycho Nightingale 	struct uart_softc *sc;
980*bf21cd93STycho Nightingale 
981*bf21cd93STycho Nightingale 	sc = malloc(sizeof(struct uart_softc));
982*bf21cd93STycho Nightingale 	bzero(sc, sizeof(struct uart_softc));
983*bf21cd93STycho Nightingale 
984*bf21cd93STycho Nightingale 	sc->arg = arg;
985*bf21cd93STycho Nightingale 	sc->intr_assert = intr_assert;
986*bf21cd93STycho Nightingale 	sc->intr_deassert = intr_deassert;
987*bf21cd93STycho Nightingale 
988*bf21cd93STycho Nightingale 	pthread_mutex_init(&sc->mtx, NULL);
989*bf21cd93STycho Nightingale 
990*bf21cd93STycho Nightingale 	uart_reset(sc);
991*bf21cd93STycho Nightingale 
992*bf21cd93STycho Nightingale 	return (sc);
993*bf21cd93STycho Nightingale }
994*bf21cd93STycho Nightingale 
995*bf21cd93STycho Nightingale int
996*bf21cd93STycho Nightingale uart_set_backend(struct uart_softc *sc, const char *opts)
997*bf21cd93STycho Nightingale {
998*bf21cd93STycho Nightingale #ifndef	__FreeBSD__
999*bf21cd93STycho Nightingale 	int error;
1000*bf21cd93STycho Nightingale #endif
1001*bf21cd93STycho Nightingale 	/*
1002*bf21cd93STycho Nightingale 	 * XXX one stdio backend supported at this time.
1003*bf21cd93STycho Nightingale 	 */
1004*bf21cd93STycho Nightingale 	if (opts == NULL)
1005*bf21cd93STycho Nightingale 		return (0);
1006*bf21cd93STycho Nightingale 
1007*bf21cd93STycho Nightingale #ifdef	__FreeBSD__
1008*bf21cd93STycho Nightingale 	if (strcmp("stdio", opts) == 0 && !uart_stdio) {
1009*bf21cd93STycho Nightingale 		sc->stdio = true;
1010*bf21cd93STycho Nightingale 		uart_stdio = true;
1011*bf21cd93STycho Nightingale 		return (0);
1012*bf21cd93STycho Nightingale #else
1013*bf21cd93STycho Nightingale 	if (strcmp("stdio", opts) == 0 && !uart_stdio && !uart_bcons) {
1014*bf21cd93STycho Nightingale 		sc->stdio = true;
1015*bf21cd93STycho Nightingale 		uart_stdio = true;
1016*bf21cd93STycho Nightingale 
1017*bf21cd93STycho Nightingale 		error = pthread_create(NULL, NULL, uart_tty_thread, sc);
1018*bf21cd93STycho Nightingale 		assert(error == 0);
1019*bf21cd93STycho Nightingale 
1020*bf21cd93STycho Nightingale 		return (0);
1021*bf21cd93STycho Nightingale 	} else if (strstr(opts, "bcons") != 0 && !uart_stdio && !uart_bcons) {
1022*bf21cd93STycho Nightingale 		sc->bcons = true;
1023*bf21cd93STycho Nightingale 		uart_bcons= true;
1024*bf21cd93STycho Nightingale 
1025*bf21cd93STycho Nightingale 		if (strstr(opts, "bcons,wait") != 0) {
1026*bf21cd93STycho Nightingale 			bcons_wait = true;
1027*bf21cd93STycho Nightingale 		}
1028*bf21cd93STycho Nightingale 
1029*bf21cd93STycho Nightingale 		sc->usc_bcons.clifd = -1;
1030*bf21cd93STycho Nightingale 		if ((sc->usc_bcons.servfd = init_bcons_sock()) == -1) {
1031*bf21cd93STycho Nightingale 			fprintf(stderr, "bhyve console setup: "
1032*bf21cd93STycho Nightingale 			    "socket initialization failed\n");
1033*bf21cd93STycho Nightingale 			return (-1);
1034*bf21cd93STycho Nightingale 		}
1035*bf21cd93STycho Nightingale 		error = pthread_create(NULL, NULL, uart_bcons_thread, sc);
1036*bf21cd93STycho Nightingale 		assert(error == 0);
1037*bf21cd93STycho Nightingale 
1038*bf21cd93STycho Nightingale 		return (0);
1039*bf21cd93STycho Nightingale #endif
1040*bf21cd93STycho Nightingale 	} else
1041*bf21cd93STycho Nightingale 		return (-1);
1042*bf21cd93STycho Nightingale }
1043