xref: /illumos-gate/usr/src/boot/efi/libefi/efiisaio.c (revision 4ac2186d79f65de18b11f2693e78f73b27d5308b)
1*4ac2186dSToomas Soome /*
2*4ac2186dSToomas Soome  * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
3*4ac2186dSToomas Soome  *
4*4ac2186dSToomas Soome  * Redistribution and use in source and binary forms, with or without
5*4ac2186dSToomas Soome  * modification, are permitted provided that the following conditions
6*4ac2186dSToomas Soome  * are met:
7*4ac2186dSToomas Soome  * 1. Redistributions of source code must retain the above copyright
8*4ac2186dSToomas Soome  *    notice, this list of conditions and the following disclaimer.
9*4ac2186dSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
10*4ac2186dSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
11*4ac2186dSToomas Soome  *    documentation and/or other materials provided with the distribution.
12*4ac2186dSToomas Soome  *
13*4ac2186dSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*4ac2186dSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*4ac2186dSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*4ac2186dSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*4ac2186dSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*4ac2186dSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*4ac2186dSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*4ac2186dSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*4ac2186dSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*4ac2186dSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*4ac2186dSToomas Soome  * SUCH DAMAGE.
24*4ac2186dSToomas Soome  */
25*4ac2186dSToomas Soome 
26*4ac2186dSToomas Soome #include <sys/cdefs.h>
27*4ac2186dSToomas Soome 
28*4ac2186dSToomas Soome #include <stand.h>
29*4ac2186dSToomas Soome #include <sys/errno.h>
30*4ac2186dSToomas Soome #include <sys/param.h>
31*4ac2186dSToomas Soome #include <bootstrap.h>
32*4ac2186dSToomas Soome #include <stdbool.h>
33*4ac2186dSToomas Soome 
34*4ac2186dSToomas Soome #include <efi.h>
35*4ac2186dSToomas Soome #include <efilib.h>
36*4ac2186dSToomas Soome #include <efidevp.h>
37*4ac2186dSToomas Soome #include <Protocol/IsaIo.h>
38*4ac2186dSToomas Soome #include <dev/ic/ns16550.h>
39*4ac2186dSToomas Soome #include <uuid.h>
40*4ac2186dSToomas Soome 
41*4ac2186dSToomas Soome #ifdef MDE_CPU_X64
42*4ac2186dSToomas Soome #include <machine/cpufunc.h>
43*4ac2186dSToomas Soome #endif
44*4ac2186dSToomas Soome 
45*4ac2186dSToomas Soome EFI_GUID  gEfiIsaIoProtocolGuid = EFI_ISA_IO_PROTOCOL_GUID;
46*4ac2186dSToomas Soome 
47*4ac2186dSToomas Soome #define	COMC_TXWAIT	0x40000		/* transmit timeout */
48*4ac2186dSToomas Soome #define	COMC_BPS(x)	(115200 / (x))	/* speed to DLAB divisor */
49*4ac2186dSToomas Soome #define	COMC_DIV2BPS(x)	(115200 / (x))	/* DLAB divisor to speed */
50*4ac2186dSToomas Soome 
51*4ac2186dSToomas Soome #ifndef COMSPEED
52*4ac2186dSToomas Soome #define	COMSPEED	9600
53*4ac2186dSToomas Soome #endif
54*4ac2186dSToomas Soome 
55*4ac2186dSToomas Soome #define	COM1_IOADDR	0x3f8
56*4ac2186dSToomas Soome #define	COM2_IOADDR	0x2f8
57*4ac2186dSToomas Soome #define	COM3_IOADDR	0x3e8
58*4ac2186dSToomas Soome #define	COM4_IOADDR	0x2e8
59*4ac2186dSToomas Soome 
60*4ac2186dSToomas Soome #ifdef MDE_CPU_X64
61*4ac2186dSToomas Soome static uint_t io_ports[] = {
62*4ac2186dSToomas Soome 	COM1_IOADDR, COM2_IOADDR, COM3_IOADDR, COM4_IOADDR
63*4ac2186dSToomas Soome };
64*4ac2186dSToomas Soome #endif
65*4ac2186dSToomas Soome 
66*4ac2186dSToomas Soome #define	STOP1		0x00
67*4ac2186dSToomas Soome #define	STOP2		0x04
68*4ac2186dSToomas Soome 
69*4ac2186dSToomas Soome #define	PARODD		0x00
70*4ac2186dSToomas Soome #define	PAREN		0x08
71*4ac2186dSToomas Soome #define	PAREVN		0x10
72*4ac2186dSToomas Soome #define	PARMARK		0x20
73*4ac2186dSToomas Soome 
74*4ac2186dSToomas Soome #define	BITS5		0x00	/* 5 bits per char */
75*4ac2186dSToomas Soome #define	BITS6		0x01	/* 6 bits per char */
76*4ac2186dSToomas Soome #define	BITS7		0x02	/* 7 bits per char */
77*4ac2186dSToomas Soome #define	BITS8		0x03	/* 8 bits per char */
78*4ac2186dSToomas Soome 
79*4ac2186dSToomas Soome #define	PNP0501		0x501		/* 16550A-compatible COM port */
80*4ac2186dSToomas Soome 
81*4ac2186dSToomas Soome static void	efi_isa_probe(struct console *);
82*4ac2186dSToomas Soome static int	efi_isa_init(struct console *, int);
83*4ac2186dSToomas Soome static void	efi_isa_putchar(struct console *, int);
84*4ac2186dSToomas Soome static int	efi_isa_getchar(struct console *);
85*4ac2186dSToomas Soome static int	efi_isa_ischar(struct console *);
86*4ac2186dSToomas Soome static int	efi_isa_ioctl(struct console *, int, void *);
87*4ac2186dSToomas Soome static void	efi_isa_devinfo(struct console *);
88*4ac2186dSToomas Soome static bool	efi_isa_setup(struct console *);
89*4ac2186dSToomas Soome static char	*efi_isa_asprint_mode(struct serial *);
90*4ac2186dSToomas Soome static int	efi_isa_parse_mode(struct serial *, const char *);
91*4ac2186dSToomas Soome static int	efi_isa_mode_set(struct env_var *, int, const void *);
92*4ac2186dSToomas Soome static int	efi_isa_cd_set(struct env_var *, int, const void *);
93*4ac2186dSToomas Soome static int	efi_isa_rtsdtr_set(struct env_var *, int, const void *);
94*4ac2186dSToomas Soome 
95*4ac2186dSToomas Soome extern struct console efi_console;
96*4ac2186dSToomas Soome 
97*4ac2186dSToomas Soome static bool
efi_isa_port_is_present(struct serial * sp)98*4ac2186dSToomas Soome efi_isa_port_is_present(struct serial *sp)
99*4ac2186dSToomas Soome {
100*4ac2186dSToomas Soome 	EFI_STATUS status;
101*4ac2186dSToomas Soome #define	COMC_TEST	0xbb
102*4ac2186dSToomas Soome 	uint8_t test = COMC_TEST;
103*4ac2186dSToomas Soome 
104*4ac2186dSToomas Soome 	/*
105*4ac2186dSToomas Soome 	 * Write byte to scratch register and read it out.
106*4ac2186dSToomas Soome 	 */
107*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Write(sp->io.isa,
108*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
109*4ac2186dSToomas Soome 	    sp->ioaddr + com_scr, 1, &test);
110*4ac2186dSToomas Soome 	test = 0;
111*4ac2186dSToomas Soome 	if (status == EFI_SUCCESS) {
112*4ac2186dSToomas Soome 		status = sp->io.isa->Io.Read(sp->io.isa,
113*4ac2186dSToomas Soome 		    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_scr,
114*4ac2186dSToomas Soome 		    1, &test);
115*4ac2186dSToomas Soome 	}
116*4ac2186dSToomas Soome 	return (test == COMC_TEST);
117*4ac2186dSToomas Soome #undef COMC_TEST
118*4ac2186dSToomas Soome }
119*4ac2186dSToomas Soome 
120*4ac2186dSToomas Soome static bool
efi_isa_should_append(const char * name,struct serial * port)121*4ac2186dSToomas Soome efi_isa_should_append(const char *name, struct serial *port)
122*4ac2186dSToomas Soome {
123*4ac2186dSToomas Soome 	EFI_DEVICE_PATH *node, *dev;
124*4ac2186dSToomas Soome 	EFI_STATUS status;
125*4ac2186dSToomas Soome 	char *buf;
126*4ac2186dSToomas Soome 	size_t sz;
127*4ac2186dSToomas Soome 	bool rv = true;
128*4ac2186dSToomas Soome 
129*4ac2186dSToomas Soome 	if (port->currdev == NULL)
130*4ac2186dSToomas Soome 		return (rv);
131*4ac2186dSToomas Soome 
132*4ac2186dSToomas Soome 	buf = NULL;
133*4ac2186dSToomas Soome 	sz = 0;
134*4ac2186dSToomas Soome 	status = efi_global_getenv(name, buf, &sz);
135*4ac2186dSToomas Soome 	if (status == EFI_BUFFER_TOO_SMALL) {
136*4ac2186dSToomas Soome 		buf = malloc(sz);
137*4ac2186dSToomas Soome 		if (buf == NULL)
138*4ac2186dSToomas Soome 			return (rv);
139*4ac2186dSToomas Soome 		status = efi_global_getenv(name, buf, &sz);
140*4ac2186dSToomas Soome 	}
141*4ac2186dSToomas Soome 	if (EFI_ERROR(status)) {
142*4ac2186dSToomas Soome 		free(buf);
143*4ac2186dSToomas Soome 		return (rv);
144*4ac2186dSToomas Soome 	}
145*4ac2186dSToomas Soome 
146*4ac2186dSToomas Soome 	dev = efi_lookup_devpath(port->currdev);
147*4ac2186dSToomas Soome 	if (dev == NULL) {
148*4ac2186dSToomas Soome 		free(buf);
149*4ac2186dSToomas Soome 		return (rv);
150*4ac2186dSToomas Soome 	}
151*4ac2186dSToomas Soome 
152*4ac2186dSToomas Soome 	node = (EFI_DEVICE_PATH *)buf;
153*4ac2186dSToomas Soome 	/*
154*4ac2186dSToomas Soome 	 * We only need to know if this port is first in list.
155*4ac2186dSToomas Soome 	 * This is only important when "os_console" is not set.
156*4ac2186dSToomas Soome 	 */
157*4ac2186dSToomas Soome 	if (!IsDevicePathEnd(node) && efi_devpath_is_prefix(dev, node))
158*4ac2186dSToomas Soome 		rv = false;
159*4ac2186dSToomas Soome 
160*4ac2186dSToomas Soome 	efi_close_devpath(dev);
161*4ac2186dSToomas Soome 	free(buf);
162*4ac2186dSToomas Soome 	return (rv);
163*4ac2186dSToomas Soome }
164*4ac2186dSToomas Soome 
165*4ac2186dSToomas Soome static void
efi_isa_setup_env(struct console * tty)166*4ac2186dSToomas Soome efi_isa_setup_env(struct console *tty)
167*4ac2186dSToomas Soome {
168*4ac2186dSToomas Soome 	struct serial *port = tty->c_private;
169*4ac2186dSToomas Soome 	char name[20];
170*4ac2186dSToomas Soome 	char value[20];
171*4ac2186dSToomas Soome 	char *env;
172*4ac2186dSToomas Soome 
173*4ac2186dSToomas Soome 	(void) snprintf(name, sizeof (name), "%s-mode", tty->c_name);
174*4ac2186dSToomas Soome 	env = getenv(name);
175*4ac2186dSToomas Soome 	if (env != NULL)
176*4ac2186dSToomas Soome 		(void) efi_isa_parse_mode(port, env);
177*4ac2186dSToomas Soome 	env = efi_isa_asprint_mode(port);
178*4ac2186dSToomas Soome 	if (env != NULL) {
179*4ac2186dSToomas Soome 		(void) unsetenv(name);
180*4ac2186dSToomas Soome 		(void) env_setenv(name, EV_VOLATILE, env, efi_isa_mode_set,
181*4ac2186dSToomas Soome 		    env_nounset);
182*4ac2186dSToomas Soome 		if (port->is_efi_console) {
183*4ac2186dSToomas Soome 			(void) snprintf(name, sizeof (name), "%s-spcr-mode",
184*4ac2186dSToomas Soome 			    tty->c_name);
185*4ac2186dSToomas Soome 			(void) setenv(name, env, 1);
186*4ac2186dSToomas Soome 			free(env);
187*4ac2186dSToomas Soome 
188*4ac2186dSToomas Soome 			/* Add us to console list. */
189*4ac2186dSToomas Soome 			(void) snprintf(name, sizeof (name), "console");
190*4ac2186dSToomas Soome 			env = getenv(name);
191*4ac2186dSToomas Soome 			if (env == NULL) {
192*4ac2186dSToomas Soome 				(void) setenv(name, tty->c_name, 1);
193*4ac2186dSToomas Soome 			} else {
194*4ac2186dSToomas Soome 				char *ptr;
195*4ac2186dSToomas Soome 				int rv;
196*4ac2186dSToomas Soome 
197*4ac2186dSToomas Soome 				/*
198*4ac2186dSToomas Soome 				 * we have "text" already in place,
199*4ac2186dSToomas Soome 				 * consult ConOut if we need to add
200*4ac2186dSToomas Soome 				 * serial console before or after.
201*4ac2186dSToomas Soome 				 */
202*4ac2186dSToomas Soome 				if (efi_isa_should_append("ConOut", port))
203*4ac2186dSToomas Soome 					rv = asprintf(&ptr, "%s,%s", env,
204*4ac2186dSToomas Soome 					    tty->c_name);
205*4ac2186dSToomas Soome 				else
206*4ac2186dSToomas Soome 					rv = asprintf(&ptr, "%s,%s",
207*4ac2186dSToomas Soome 					    tty->c_name, env);
208*4ac2186dSToomas Soome 				if (rv > 0) {
209*4ac2186dSToomas Soome 					(void) setenv(name, ptr, 1);
210*4ac2186dSToomas Soome 					free(ptr);
211*4ac2186dSToomas Soome 				} else {
212*4ac2186dSToomas Soome 					printf("%s: %s\n", __func__,
213*4ac2186dSToomas Soome 					    strerror(ENOMEM));
214*4ac2186dSToomas Soome 				}
215*4ac2186dSToomas Soome 			}
216*4ac2186dSToomas Soome 		} else {
217*4ac2186dSToomas Soome 			free(env);
218*4ac2186dSToomas Soome 		}
219*4ac2186dSToomas Soome 	}
220*4ac2186dSToomas Soome 
221*4ac2186dSToomas Soome 	(void) snprintf(name, sizeof (name), "%s-ignore-cd", tty->c_name);
222*4ac2186dSToomas Soome 	env = getenv(name);
223*4ac2186dSToomas Soome 	if (env != NULL) {
224*4ac2186dSToomas Soome 		if (strcmp(env, "true") == 0)
225*4ac2186dSToomas Soome 			port->ignore_cd = 1;
226*4ac2186dSToomas Soome 		else if (strcmp(env, "false") == 0)
227*4ac2186dSToomas Soome 			port->ignore_cd = 0;
228*4ac2186dSToomas Soome 	}
229*4ac2186dSToomas Soome 
230*4ac2186dSToomas Soome 	(void) snprintf(value, sizeof (value), "%s",
231*4ac2186dSToomas Soome 	    port->ignore_cd? "true" : "false");
232*4ac2186dSToomas Soome 	(void) unsetenv(name);
233*4ac2186dSToomas Soome 	(void) env_setenv(name, EV_VOLATILE, value, efi_isa_cd_set,
234*4ac2186dSToomas Soome 	    env_nounset);
235*4ac2186dSToomas Soome 
236*4ac2186dSToomas Soome 	(void) snprintf(name, sizeof (name), "%s-rts-dtr-off", tty->c_name);
237*4ac2186dSToomas Soome 	env = getenv(name);
238*4ac2186dSToomas Soome 	if (env != NULL) {
239*4ac2186dSToomas Soome 		if (strcmp(env, "true") == 0)
240*4ac2186dSToomas Soome 			port->rtsdtr_off = 1;
241*4ac2186dSToomas Soome 		else if (strcmp(env, "false") == 0)
242*4ac2186dSToomas Soome 			port->rtsdtr_off = 0;
243*4ac2186dSToomas Soome 	}
244*4ac2186dSToomas Soome 
245*4ac2186dSToomas Soome 	(void) snprintf(value, sizeof (value), "%s",
246*4ac2186dSToomas Soome 	    port->rtsdtr_off? "true" : "false");
247*4ac2186dSToomas Soome 	(void) unsetenv(name);
248*4ac2186dSToomas Soome 	(void) env_setenv(name, EV_VOLATILE, value, efi_isa_rtsdtr_set,
249*4ac2186dSToomas Soome 	    env_nounset);
250*4ac2186dSToomas Soome }
251*4ac2186dSToomas Soome 
252*4ac2186dSToomas Soome static void
efi_check_and_set_condev(struct serial * port,const char * name)253*4ac2186dSToomas Soome efi_check_and_set_condev(struct serial *port, const char *name)
254*4ac2186dSToomas Soome {
255*4ac2186dSToomas Soome 	EFI_DEVICE_PATH *node, *dev;
256*4ac2186dSToomas Soome 	EFI_STATUS status;
257*4ac2186dSToomas Soome 	char *buf;
258*4ac2186dSToomas Soome 	size_t sz;
259*4ac2186dSToomas Soome 
260*4ac2186dSToomas Soome 	if (port->currdev == NULL)
261*4ac2186dSToomas Soome 		return;
262*4ac2186dSToomas Soome 
263*4ac2186dSToomas Soome 	buf = NULL;
264*4ac2186dSToomas Soome 	sz = 0;
265*4ac2186dSToomas Soome 	status = efi_global_getenv(name, buf, &sz);
266*4ac2186dSToomas Soome 	if (status == EFI_BUFFER_TOO_SMALL) {
267*4ac2186dSToomas Soome 		buf = malloc(sz);
268*4ac2186dSToomas Soome 		if (buf == NULL)
269*4ac2186dSToomas Soome 			return;
270*4ac2186dSToomas Soome 		status = efi_global_getenv(name, buf, &sz);
271*4ac2186dSToomas Soome 	}
272*4ac2186dSToomas Soome 	if (EFI_ERROR(status)) {
273*4ac2186dSToomas Soome 		free(buf);
274*4ac2186dSToomas Soome 		return;
275*4ac2186dSToomas Soome 	}
276*4ac2186dSToomas Soome 
277*4ac2186dSToomas Soome 	dev = efi_lookup_devpath(port->currdev);
278*4ac2186dSToomas Soome 	if (dev == NULL) {
279*4ac2186dSToomas Soome 		free(buf);
280*4ac2186dSToomas Soome 		return;
281*4ac2186dSToomas Soome 	}
282*4ac2186dSToomas Soome 
283*4ac2186dSToomas Soome 	node = (EFI_DEVICE_PATH *)buf;
284*4ac2186dSToomas Soome 	while (!IsDevicePathEnd(node)) {
285*4ac2186dSToomas Soome 		/* Sanity check the node before moving to the next node. */
286*4ac2186dSToomas Soome 		if (DevicePathNodeLength(node) < sizeof (*node))
287*4ac2186dSToomas Soome 			break;
288*4ac2186dSToomas Soome 
289*4ac2186dSToomas Soome 		if (efi_devpath_is_prefix(dev, node)) {
290*4ac2186dSToomas Soome 			port->is_efi_console = true;
291*4ac2186dSToomas Soome 			break;
292*4ac2186dSToomas Soome 		}
293*4ac2186dSToomas Soome 
294*4ac2186dSToomas Soome 		node = efi_devpath_next_instance(node);
295*4ac2186dSToomas Soome 	}
296*4ac2186dSToomas Soome 
297*4ac2186dSToomas Soome 	efi_close_devpath(dev);
298*4ac2186dSToomas Soome 	free(buf);
299*4ac2186dSToomas Soome }
300*4ac2186dSToomas Soome 
301*4ac2186dSToomas Soome /*
302*4ac2186dSToomas Soome  * Return number of ports created (0 or 1).
303*4ac2186dSToomas Soome  */
304*4ac2186dSToomas Soome static uint_t
efi_isa_create_port(EFI_HANDLE handle)305*4ac2186dSToomas Soome efi_isa_create_port(EFI_HANDLE handle)
306*4ac2186dSToomas Soome {
307*4ac2186dSToomas Soome 	struct serial *port;
308*4ac2186dSToomas Soome 	EFI_ISA_IO_PROTOCOL *io;
309*4ac2186dSToomas Soome 	EFI_STATUS status;
310*4ac2186dSToomas Soome 
311*4ac2186dSToomas Soome 	status = BS->OpenProtocol(handle, &gEfiIsaIoProtocolGuid,
312*4ac2186dSToomas Soome 	    (void**)&io, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
313*4ac2186dSToomas Soome 	if (EFI_ERROR(status)) {
314*4ac2186dSToomas Soome 		return (0);
315*4ac2186dSToomas Soome 	}
316*4ac2186dSToomas Soome 
317*4ac2186dSToomas Soome 	/* Is this serial port? */
318*4ac2186dSToomas Soome 	if (io->ResourceList->Device.HID != EISA_PNP_ID(PNP0501))
319*4ac2186dSToomas Soome 		return (0);
320*4ac2186dSToomas Soome 
321*4ac2186dSToomas Soome 	/* We assume I/O port */
322*4ac2186dSToomas Soome 	if (io->ResourceList->ResourceItem->Type != EfiIsaAcpiResourceIo)
323*4ac2186dSToomas Soome 		return (0);
324*4ac2186dSToomas Soome 
325*4ac2186dSToomas Soome 	port = calloc(1, sizeof (*port));
326*4ac2186dSToomas Soome 	if (port == NULL) {
327*4ac2186dSToomas Soome 		return (0);
328*4ac2186dSToomas Soome 	}
329*4ac2186dSToomas Soome 
330*4ac2186dSToomas Soome 	/* Set up port descriptor */
331*4ac2186dSToomas Soome 	port->ignore_cd = true;
332*4ac2186dSToomas Soome 	port->currdev = handle;
333*4ac2186dSToomas Soome 	port->ioaddr = 0;
334*4ac2186dSToomas Soome 	for (uint_t i = 0; io->ResourceList->ResourceItem[i].Type !=
335*4ac2186dSToomas Soome 	    EfiIsaAcpiResourceEndOfList; i++) {
336*4ac2186dSToomas Soome 		if (io->ResourceList->ResourceItem[i].Type ==
337*4ac2186dSToomas Soome 		    EfiIsaAcpiResourceIo) {
338*4ac2186dSToomas Soome 			port->ioaddr =
339*4ac2186dSToomas Soome 			    io->ResourceList->ResourceItem[i].StartRange;
340*4ac2186dSToomas Soome 			break;
341*4ac2186dSToomas Soome 		}
342*4ac2186dSToomas Soome 	}
343*4ac2186dSToomas Soome 	port->guid = &gEfiIsaIoProtocolGuid;
344*4ac2186dSToomas Soome 	port->io.isa = io;
345*4ac2186dSToomas Soome 	/* Use 8,n,1 for defaults */
346*4ac2186dSToomas Soome 	port->databits = 8;
347*4ac2186dSToomas Soome 	port->parity = NoParity;
348*4ac2186dSToomas Soome 	port->stopbits = OneStopBit;
349*4ac2186dSToomas Soome 
350*4ac2186dSToomas Soome 	STAILQ_INSERT_TAIL(&serials, port, next);
351*4ac2186dSToomas Soome 	return (1);
352*4ac2186dSToomas Soome }
353*4ac2186dSToomas Soome 
354*4ac2186dSToomas Soome #ifdef MDE_CPU_X64
355*4ac2186dSToomas Soome static EFI_STATUS
efi_isa_create_io(EFI_ISA_IO_PROTOCOL ** iop)356*4ac2186dSToomas Soome efi_isa_create_io(EFI_ISA_IO_PROTOCOL **iop)
357*4ac2186dSToomas Soome {
358*4ac2186dSToomas Soome 	EFI_ISA_IO_PROTOCOL *io;
359*4ac2186dSToomas Soome 
360*4ac2186dSToomas Soome 	io = calloc(1, sizeof (*io));
361*4ac2186dSToomas Soome 	if (io == NULL) {
362*4ac2186dSToomas Soome 		return (EFI_OUT_OF_RESOURCES);
363*4ac2186dSToomas Soome 	}
364*4ac2186dSToomas Soome 	io->ResourceList = malloc(sizeof (*io->ResourceList));
365*4ac2186dSToomas Soome 	if (io->ResourceList == NULL) {
366*4ac2186dSToomas Soome 		free(io);
367*4ac2186dSToomas Soome 		return (EFI_OUT_OF_RESOURCES);
368*4ac2186dSToomas Soome 	}
369*4ac2186dSToomas Soome 	io->ResourceList->ResourceItem =
370*4ac2186dSToomas Soome 	    calloc(2, sizeof (*io->ResourceList->ResourceItem));
371*4ac2186dSToomas Soome 	if (io->ResourceList == NULL) {
372*4ac2186dSToomas Soome 		free(io->ResourceList);
373*4ac2186dSToomas Soome 		free(io);
374*4ac2186dSToomas Soome 		return (EFI_OUT_OF_RESOURCES);
375*4ac2186dSToomas Soome 	}
376*4ac2186dSToomas Soome 
377*4ac2186dSToomas Soome 	*iop = io;
378*4ac2186dSToomas Soome 	return (EFI_SUCCESS);
379*4ac2186dSToomas Soome }
380*4ac2186dSToomas Soome 
381*4ac2186dSToomas Soome static EFI_STATUS EFIAPI
_Read(EFI_ISA_IO_PROTOCOL * this __unused,EFI_ISA_IO_PROTOCOL_WIDTH Width __unused,UINT32 Offset,UINTN Count,VOID * Buffer)382*4ac2186dSToomas Soome _Read(EFI_ISA_IO_PROTOCOL *this __unused,
383*4ac2186dSToomas Soome     EFI_ISA_IO_PROTOCOL_WIDTH Width __unused,
384*4ac2186dSToomas Soome     UINT32 Offset, UINTN Count, VOID *Buffer)
385*4ac2186dSToomas Soome {
386*4ac2186dSToomas Soome 	uint8_t *buf = (uint8_t *)Buffer;
387*4ac2186dSToomas Soome 
388*4ac2186dSToomas Soome 	while ((Count--) != 0) {
389*4ac2186dSToomas Soome 		*buf++ = inb(Offset);
390*4ac2186dSToomas Soome 	}
391*4ac2186dSToomas Soome 
392*4ac2186dSToomas Soome 	return (EFI_SUCCESS);
393*4ac2186dSToomas Soome }
394*4ac2186dSToomas Soome 
395*4ac2186dSToomas Soome static EFI_STATUS EFIAPI
_Write(EFI_ISA_IO_PROTOCOL * this __unused,EFI_ISA_IO_PROTOCOL_WIDTH Width __unused,UINT32 Offset,UINTN Count,VOID * Buffer)396*4ac2186dSToomas Soome _Write(EFI_ISA_IO_PROTOCOL *this __unused,
397*4ac2186dSToomas Soome     EFI_ISA_IO_PROTOCOL_WIDTH Width __unused,
398*4ac2186dSToomas Soome     UINT32 Offset, UINTN Count, VOID *Buffer)
399*4ac2186dSToomas Soome {
400*4ac2186dSToomas Soome 	uint8_t *buf = (uint8_t *)Buffer;
401*4ac2186dSToomas Soome 
402*4ac2186dSToomas Soome 	while ((Count--) != 0) {
403*4ac2186dSToomas Soome 		outb(Offset, *buf++);
404*4ac2186dSToomas Soome 	}
405*4ac2186dSToomas Soome 	return (EFI_SUCCESS);
406*4ac2186dSToomas Soome }
407*4ac2186dSToomas Soome 
408*4ac2186dSToomas Soome static EFI_STATUS
efi_isa_create_io_ports(void)409*4ac2186dSToomas Soome efi_isa_create_io_ports(void)
410*4ac2186dSToomas Soome {
411*4ac2186dSToomas Soome 	struct serial *port;
412*4ac2186dSToomas Soome 	EFI_ISA_IO_PROTOCOL *io;
413*4ac2186dSToomas Soome 	EFI_STATUS status = EFI_SUCCESS;
414*4ac2186dSToomas Soome 
415*4ac2186dSToomas Soome 	port = NULL;
416*4ac2186dSToomas Soome 	for (uint_t i = 0; i < nitems(io_ports); i++) {
417*4ac2186dSToomas Soome 		if (port == NULL) {
418*4ac2186dSToomas Soome 			status = efi_isa_create_io(&io);
419*4ac2186dSToomas Soome 			if (EFI_ERROR(status))
420*4ac2186dSToomas Soome 				return (status);
421*4ac2186dSToomas Soome 			io->Io.Read = _Read;
422*4ac2186dSToomas Soome 			io->Io.Write = _Write;
423*4ac2186dSToomas Soome 			io->ResourceList->Device.HID = EISA_PNP_ID(PNP0501);
424*4ac2186dSToomas Soome 			io->ResourceList->ResourceItem[0].Type =
425*4ac2186dSToomas Soome 			    EfiIsaAcpiResourceIo;
426*4ac2186dSToomas Soome 			io->ResourceList->ResourceItem[1].Type =
427*4ac2186dSToomas Soome 			    EfiIsaAcpiResourceEndOfList;
428*4ac2186dSToomas Soome 
429*4ac2186dSToomas Soome 			port = calloc(1, sizeof (*port));
430*4ac2186dSToomas Soome 			if (port == NULL) {
431*4ac2186dSToomas Soome 				free(io->ResourceList->ResourceItem);
432*4ac2186dSToomas Soome 				free(io->ResourceList);
433*4ac2186dSToomas Soome 				free(io);
434*4ac2186dSToomas Soome 				return (EFI_OUT_OF_RESOURCES);
435*4ac2186dSToomas Soome 			}
436*4ac2186dSToomas Soome 			/* Set up port descriptor */
437*4ac2186dSToomas Soome 			port->io.isa = io;
438*4ac2186dSToomas Soome 			/* Use 8,n,1 for defaults */
439*4ac2186dSToomas Soome 			port->databits = 8;
440*4ac2186dSToomas Soome 			port->parity = NoParity;
441*4ac2186dSToomas Soome 			port->stopbits = OneStopBit;
442*4ac2186dSToomas Soome 			port->ignore_cd = true;
443*4ac2186dSToomas Soome 			port->guid = &gEfiIsaIoProtocolGuid;
444*4ac2186dSToomas Soome 		}
445*4ac2186dSToomas Soome 		io->ResourceList->Device.UID = i;
446*4ac2186dSToomas Soome 		io->ResourceList->ResourceItem[0].StartRange = io_ports[i];
447*4ac2186dSToomas Soome 		port->ioaddr = io_ports[i];
448*4ac2186dSToomas Soome 		if (efi_isa_port_is_present(port)) {
449*4ac2186dSToomas Soome 			STAILQ_INSERT_TAIL(&serials, port, next);
450*4ac2186dSToomas Soome 			port = NULL;
451*4ac2186dSToomas Soome 		}
452*4ac2186dSToomas Soome 	}
453*4ac2186dSToomas Soome 
454*4ac2186dSToomas Soome 	if (port != NULL) {
455*4ac2186dSToomas Soome 		free(io->ResourceList->ResourceItem);
456*4ac2186dSToomas Soome 		free(io->ResourceList);
457*4ac2186dSToomas Soome 		free(io);
458*4ac2186dSToomas Soome 		free(port);
459*4ac2186dSToomas Soome 	}
460*4ac2186dSToomas Soome 	return (status);
461*4ac2186dSToomas Soome }
462*4ac2186dSToomas Soome #endif	/* MDE_CPU_X64 */
463*4ac2186dSToomas Soome 
464*4ac2186dSToomas Soome /*
465*4ac2186dSToomas Soome  * Get IsaIo protocol handles and build port list for us.
466*4ac2186dSToomas Soome  * returns EFI_SUCCESS or EFI_NOT_FOUND.
467*4ac2186dSToomas Soome  */
468*4ac2186dSToomas Soome static EFI_STATUS
efi_isa_probe_ports(void)469*4ac2186dSToomas Soome efi_isa_probe_ports(void)
470*4ac2186dSToomas Soome {
471*4ac2186dSToomas Soome 	EFI_STATUS status;
472*4ac2186dSToomas Soome 	EFI_HANDLE *handles;
473*4ac2186dSToomas Soome 	struct serial *port;
474*4ac2186dSToomas Soome 	uint_t count, nhandles, index;
475*4ac2186dSToomas Soome 
476*4ac2186dSToomas Soome 	count = 0;
477*4ac2186dSToomas Soome 	nhandles = 0;
478*4ac2186dSToomas Soome 	handles = NULL;
479*4ac2186dSToomas Soome 	status = efi_get_protocol_handles(&gEfiIsaIoProtocolGuid,
480*4ac2186dSToomas Soome 	    &nhandles, &handles);
481*4ac2186dSToomas Soome 	if (!EFI_ERROR(status)) {
482*4ac2186dSToomas Soome 		for (index = 0; index < nhandles; index++) {
483*4ac2186dSToomas Soome 			/* skip if we are iodev for serialio port */
484*4ac2186dSToomas Soome 			STAILQ_FOREACH(port, &serials, next) {
485*4ac2186dSToomas Soome 				if (port->iodev == handles[index])
486*4ac2186dSToomas Soome 					break;
487*4ac2186dSToomas Soome 			}
488*4ac2186dSToomas Soome 			if (port == NULL)
489*4ac2186dSToomas Soome 				count += efi_isa_create_port(handles[index]);
490*4ac2186dSToomas Soome 		}
491*4ac2186dSToomas Soome 		free(handles);
492*4ac2186dSToomas Soome 		if (count == 0)
493*4ac2186dSToomas Soome 			status = EFI_NOT_FOUND;
494*4ac2186dSToomas Soome 	}
495*4ac2186dSToomas Soome 	return (status);
496*4ac2186dSToomas Soome }
497*4ac2186dSToomas Soome 
498*4ac2186dSToomas Soome /*
499*4ac2186dSToomas Soome  * Set up list of possible serial consoles.
500*4ac2186dSToomas Soome  * This function is run very early, so we do not expect to
501*4ac2186dSToomas Soome  * run out of memory, and on error, we can not print output.
502*4ac2186dSToomas Soome  *
503*4ac2186dSToomas Soome  * isaio protocols can include serial ports, parallel ports,
504*4ac2186dSToomas Soome  * keyboard, mouse. We walk protocol handles, create list of
505*4ac2186dSToomas Soome  * serial ports, then create console descriptors.
506*4ac2186dSToomas Soome  */
507*4ac2186dSToomas Soome void
efi_isa_ini(void)508*4ac2186dSToomas Soome efi_isa_ini(void)
509*4ac2186dSToomas Soome {
510*4ac2186dSToomas Soome 	EFI_STATUS status;
511*4ac2186dSToomas Soome 	uint_t c, n;
512*4ac2186dSToomas Soome 	struct console **tmp;
513*4ac2186dSToomas Soome 	struct console *tty;
514*4ac2186dSToomas Soome 	struct serial *port;
515*4ac2186dSToomas Soome 
516*4ac2186dSToomas Soome 	status = efi_isa_probe_ports();
517*4ac2186dSToomas Soome #ifdef MDE_CPU_X64
518*4ac2186dSToomas Soome 	if (status == EFI_NOT_FOUND) {
519*4ac2186dSToomas Soome 		/*
520*4ac2186dSToomas Soome 		 * We have no IsaIo serial ports. But, as this implementation
521*4ac2186dSToomas Soome 		 * is very similar to one used in BIOS comconsole driver,
522*4ac2186dSToomas Soome 		 * and in order to avoid using comconsole as last resort
523*4ac2186dSToomas Soome 		 * fallback on x86 platform, we implement fake IsaIo.
524*4ac2186dSToomas Soome 		 */
525*4ac2186dSToomas Soome 		if (STAILQ_EMPTY(&serials))
526*4ac2186dSToomas Soome 			status = efi_isa_create_io_ports();
527*4ac2186dSToomas Soome 	}
528*4ac2186dSToomas Soome #endif
529*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
530*4ac2186dSToomas Soome 		return;
531*4ac2186dSToomas Soome 
532*4ac2186dSToomas Soome 	n = 0;
533*4ac2186dSToomas Soome 	/* Count ports we have */
534*4ac2186dSToomas Soome 	STAILQ_FOREACH(port, &serials, next) {
535*4ac2186dSToomas Soome 		if (uuid_equal((uuid_t *)port->guid,
536*4ac2186dSToomas Soome 		    (uuid_t *)&gEfiIsaIoProtocolGuid, NULL) == 1)
537*4ac2186dSToomas Soome 			n++;
538*4ac2186dSToomas Soome 	}
539*4ac2186dSToomas Soome 
540*4ac2186dSToomas Soome 	if (n == 0)
541*4ac2186dSToomas Soome 		return;		/* no serial ports here */
542*4ac2186dSToomas Soome 
543*4ac2186dSToomas Soome 	c = cons_array_size();
544*4ac2186dSToomas Soome 	if (c == 0)
545*4ac2186dSToomas Soome 		n++;	/* For NULL pointer */
546*4ac2186dSToomas Soome 
547*4ac2186dSToomas Soome 	tmp = realloc(consoles, (c + n) * sizeof (*consoles));
548*4ac2186dSToomas Soome 	if (tmp == NULL) {
549*4ac2186dSToomas Soome 		return;
550*4ac2186dSToomas Soome 	}
551*4ac2186dSToomas Soome 	consoles = tmp;
552*4ac2186dSToomas Soome 	if (c > 0)
553*4ac2186dSToomas Soome 		c--;
554*4ac2186dSToomas Soome 
555*4ac2186dSToomas Soome 	STAILQ_FOREACH(port, &serials, next) {
556*4ac2186dSToomas Soome 		char id;
557*4ac2186dSToomas Soome 
558*4ac2186dSToomas Soome 		if (uuid_equal((uuid_t *)port->guid,
559*4ac2186dSToomas Soome 		    (uuid_t *)&gEfiIsaIoProtocolGuid, NULL) == 0) {
560*4ac2186dSToomas Soome 			continue;
561*4ac2186dSToomas Soome 		}
562*4ac2186dSToomas Soome 
563*4ac2186dSToomas Soome 		tty = calloc(1, sizeof (*tty));
564*4ac2186dSToomas Soome 		if (tty == NULL) {
565*4ac2186dSToomas Soome 			/* Out of memory?! */
566*4ac2186dSToomas Soome 			continue;
567*4ac2186dSToomas Soome 		}
568*4ac2186dSToomas Soome 		switch (port->ioaddr) {
569*4ac2186dSToomas Soome 		case 0:	/* bad ioaddr */
570*4ac2186dSToomas Soome 			continue;
571*4ac2186dSToomas Soome 		case COM1_IOADDR:
572*4ac2186dSToomas Soome 			id = 'a';
573*4ac2186dSToomas Soome 			break;
574*4ac2186dSToomas Soome 		case COM2_IOADDR:
575*4ac2186dSToomas Soome 			id = 'b';
576*4ac2186dSToomas Soome 			break;
577*4ac2186dSToomas Soome 		case COM3_IOADDR:
578*4ac2186dSToomas Soome 			id = 'c';
579*4ac2186dSToomas Soome 			break;
580*4ac2186dSToomas Soome 		case COM4_IOADDR:
581*4ac2186dSToomas Soome 			id = 'd';
582*4ac2186dSToomas Soome 			break;
583*4ac2186dSToomas Soome 		default:
584*4ac2186dSToomas Soome 			/*
585*4ac2186dSToomas Soome 			 * We should not see this happening, but assigning
586*4ac2186dSToomas Soome 			 * this id would let us help to identify unexpected
587*4ac2186dSToomas Soome 			 * configuration.
588*4ac2186dSToomas Soome 			 */
589*4ac2186dSToomas Soome 			id = '0';
590*4ac2186dSToomas Soome 		}
591*4ac2186dSToomas Soome 		/* Set up serial device descriptor */
592*4ac2186dSToomas Soome 		(void) asprintf(&tty->c_name, "tty%c", id);
593*4ac2186dSToomas Soome 		(void) asprintf(&tty->c_desc, "serial port %c", id);
594*4ac2186dSToomas Soome 		tty->c_flags = C_PRESENTIN | C_PRESENTOUT;
595*4ac2186dSToomas Soome 		tty->c_probe = efi_isa_probe;
596*4ac2186dSToomas Soome 		tty->c_init = efi_isa_init;
597*4ac2186dSToomas Soome 		tty->c_out = efi_isa_putchar;
598*4ac2186dSToomas Soome 		tty->c_in = efi_isa_getchar;
599*4ac2186dSToomas Soome 		tty->c_ready = efi_isa_ischar;
600*4ac2186dSToomas Soome 		tty->c_ioctl = efi_isa_ioctl;
601*4ac2186dSToomas Soome 		tty->c_devinfo = efi_isa_devinfo;
602*4ac2186dSToomas Soome 		tty->c_private = port;
603*4ac2186dSToomas Soome 		consoles[c++] = tty;
604*4ac2186dSToomas Soome 
605*4ac2186dSToomas Soome 		/* Reset terminal to initial normal settings with ESC [ 0 m */
606*4ac2186dSToomas Soome 		efi_isa_putchar(tty, 0x1b);
607*4ac2186dSToomas Soome 		efi_isa_putchar(tty, '[');
608*4ac2186dSToomas Soome 		efi_isa_putchar(tty, '0');
609*4ac2186dSToomas Soome 		efi_isa_putchar(tty, 'm');
610*4ac2186dSToomas Soome 		/* drain input from random data */
611*4ac2186dSToomas Soome 		while (efi_isa_getchar(tty) != -1)
612*4ac2186dSToomas Soome 			;
613*4ac2186dSToomas Soome 	}
614*4ac2186dSToomas Soome 	consoles[c] = NULL;
615*4ac2186dSToomas Soome }
616*4ac2186dSToomas Soome 
617*4ac2186dSToomas Soome static EFI_STATUS
efi_isa_getspeed(struct serial * sp)618*4ac2186dSToomas Soome efi_isa_getspeed(struct serial *sp)
619*4ac2186dSToomas Soome {
620*4ac2186dSToomas Soome 	EFI_STATUS status;
621*4ac2186dSToomas Soome 	uint_t  divisor;
622*4ac2186dSToomas Soome 	uchar_t dlbh;
623*4ac2186dSToomas Soome 	uchar_t dlbl;
624*4ac2186dSToomas Soome 	uchar_t cfcr;
625*4ac2186dSToomas Soome 	uchar_t c;
626*4ac2186dSToomas Soome 
627*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Read(sp->io.isa,
628*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_cfcr, 1, &cfcr);
629*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
630*4ac2186dSToomas Soome 		return (status);
631*4ac2186dSToomas Soome 	c = CFCR_DLAB | cfcr;
632*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Write(sp->io.isa,
633*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_cfcr, 1, &c);
634*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
635*4ac2186dSToomas Soome 		return (status);
636*4ac2186dSToomas Soome 
637*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Read(sp->io.isa,
638*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_dlbl, 1, &dlbl);
639*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
640*4ac2186dSToomas Soome 		return (status);
641*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Read(sp->io.isa,
642*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_dlbh, 1, &dlbh);
643*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
644*4ac2186dSToomas Soome 		return (status);
645*4ac2186dSToomas Soome 
646*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Write(sp->io.isa,
647*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_cfcr, 1, &cfcr);
648*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
649*4ac2186dSToomas Soome 		return (status);
650*4ac2186dSToomas Soome 
651*4ac2186dSToomas Soome 	divisor = dlbh << 8 | dlbl;
652*4ac2186dSToomas Soome 
653*4ac2186dSToomas Soome 	if (divisor == 0)
654*4ac2186dSToomas Soome 		return (EFI_DEVICE_ERROR);
655*4ac2186dSToomas Soome 
656*4ac2186dSToomas Soome 	sp->baudrate = COMC_DIV2BPS(divisor);
657*4ac2186dSToomas Soome 	return (EFI_SUCCESS);
658*4ac2186dSToomas Soome }
659*4ac2186dSToomas Soome 
660*4ac2186dSToomas Soome static void
efi_isa_probe(struct console * cp)661*4ac2186dSToomas Soome efi_isa_probe(struct console *cp)
662*4ac2186dSToomas Soome {
663*4ac2186dSToomas Soome 	struct serial *sp = cp->c_private;
664*4ac2186dSToomas Soome 	EFI_STATUS status;
665*4ac2186dSToomas Soome 	uint8_t lcr;
666*4ac2186dSToomas Soome 
667*4ac2186dSToomas Soome 	if (!efi_isa_port_is_present(sp)) {
668*4ac2186dSToomas Soome 		return;
669*4ac2186dSToomas Soome 	}
670*4ac2186dSToomas Soome 
671*4ac2186dSToomas Soome 	status = efi_isa_getspeed(sp);
672*4ac2186dSToomas Soome 	if (EFI_ERROR(status)) {
673*4ac2186dSToomas Soome 		/* Use fallback value. */
674*4ac2186dSToomas Soome 		sp->baudrate = COMSPEED;
675*4ac2186dSToomas Soome 	}
676*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Read(sp->io.isa,
677*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_lcr,
678*4ac2186dSToomas Soome 	    1, &lcr);
679*4ac2186dSToomas Soome 	if (EFI_ERROR(status)) {
680*4ac2186dSToomas Soome 		return;
681*4ac2186dSToomas Soome 	}
682*4ac2186dSToomas Soome 
683*4ac2186dSToomas Soome 	sp->databits = (lcr & BITS8) == BITS8? 8:7;
684*4ac2186dSToomas Soome 	sp->stopbits = (lcr & STOP2) == STOP2? TwoStopBits:OneStopBit;
685*4ac2186dSToomas Soome 	if ((lcr & (PAREN|PAREVN)) == (PAREN|PAREVN))
686*4ac2186dSToomas Soome 		sp->parity = EvenParity;
687*4ac2186dSToomas Soome 	else if ((lcr & PAREN) == PAREN)
688*4ac2186dSToomas Soome 		sp->parity = OddParity;
689*4ac2186dSToomas Soome 	else
690*4ac2186dSToomas Soome 		sp->parity = NoParity;
691*4ac2186dSToomas Soome 
692*4ac2186dSToomas Soome 	/* check if we are listed in ConIn */
693*4ac2186dSToomas Soome 	efi_check_and_set_condev(sp, "ConIn");
694*4ac2186dSToomas Soome 	efi_isa_setup_env(cp);
695*4ac2186dSToomas Soome 	if (!efi_isa_setup(cp))
696*4ac2186dSToomas Soome 		printf("Failed to set up %s\n", cp->c_name);
697*4ac2186dSToomas Soome }
698*4ac2186dSToomas Soome 
699*4ac2186dSToomas Soome static int
efi_isa_init(struct console * cp,int arg __unused)700*4ac2186dSToomas Soome efi_isa_init(struct console *cp, int arg __unused)
701*4ac2186dSToomas Soome {
702*4ac2186dSToomas Soome 
703*4ac2186dSToomas Soome 	if (efi_isa_setup(cp))
704*4ac2186dSToomas Soome 		return (CMD_OK);
705*4ac2186dSToomas Soome 
706*4ac2186dSToomas Soome 	cp->c_flags = 0;
707*4ac2186dSToomas Soome 	return (CMD_ERROR);
708*4ac2186dSToomas Soome }
709*4ac2186dSToomas Soome 
710*4ac2186dSToomas Soome static void
efi_isa_putchar(struct console * cp,int c)711*4ac2186dSToomas Soome efi_isa_putchar(struct console *cp, int c)
712*4ac2186dSToomas Soome {
713*4ac2186dSToomas Soome 	int wait;
714*4ac2186dSToomas Soome 	EFI_STATUS status;
715*4ac2186dSToomas Soome 	UINTN bufsz = 1;
716*4ac2186dSToomas Soome 	char control, cb = c;
717*4ac2186dSToomas Soome 	struct serial *sp = cp->c_private;
718*4ac2186dSToomas Soome 
719*4ac2186dSToomas Soome 	for (wait = COMC_TXWAIT; wait > 0; wait--) {
720*4ac2186dSToomas Soome 		status = sp->io.isa->Io.Read(sp->io.isa,
721*4ac2186dSToomas Soome 		    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_lsr,
722*4ac2186dSToomas Soome 		    bufsz, &control);
723*4ac2186dSToomas Soome 		if (EFI_ERROR(status))
724*4ac2186dSToomas Soome 			continue;
725*4ac2186dSToomas Soome 
726*4ac2186dSToomas Soome 		if ((control & LSR_TXRDY) != LSR_TXRDY)
727*4ac2186dSToomas Soome 			continue;
728*4ac2186dSToomas Soome 
729*4ac2186dSToomas Soome 		status = sp->io.isa->Io.Write(sp->io.isa,
730*4ac2186dSToomas Soome 		    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT, sp->ioaddr + com_data,
731*4ac2186dSToomas Soome 		    bufsz, &cb);
732*4ac2186dSToomas Soome 		if (status != EFI_TIMEOUT)
733*4ac2186dSToomas Soome 			break;
734*4ac2186dSToomas Soome 	}
735*4ac2186dSToomas Soome }
736*4ac2186dSToomas Soome 
737*4ac2186dSToomas Soome static int
efi_isa_getchar(struct console * cp)738*4ac2186dSToomas Soome efi_isa_getchar(struct console *cp)
739*4ac2186dSToomas Soome {
740*4ac2186dSToomas Soome 	EFI_STATUS status;
741*4ac2186dSToomas Soome 	UINTN bufsz = 1;
742*4ac2186dSToomas Soome 	char c;
743*4ac2186dSToomas Soome 	struct serial *sp = cp->c_private;
744*4ac2186dSToomas Soome 
745*4ac2186dSToomas Soome 	/*
746*4ac2186dSToomas Soome 	 * if this device is also used as ConIn, some firmwares
747*4ac2186dSToomas Soome 	 * fail to return all input via SIO protocol.
748*4ac2186dSToomas Soome 	 */
749*4ac2186dSToomas Soome 	if (sp->is_efi_console) {
750*4ac2186dSToomas Soome 		return (efi_console.c_in(&efi_console));
751*4ac2186dSToomas Soome 	}
752*4ac2186dSToomas Soome 
753*4ac2186dSToomas Soome 	if (!efi_isa_ischar(cp))
754*4ac2186dSToomas Soome 		return (-1);
755*4ac2186dSToomas Soome 
756*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Read(sp->io.isa,
757*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
758*4ac2186dSToomas Soome 	    sp->ioaddr + com_data, bufsz, &c);
759*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
760*4ac2186dSToomas Soome 		return (-1);
761*4ac2186dSToomas Soome 
762*4ac2186dSToomas Soome 	return (c);
763*4ac2186dSToomas Soome }
764*4ac2186dSToomas Soome 
765*4ac2186dSToomas Soome static int
efi_isa_ischar(struct console * cp)766*4ac2186dSToomas Soome efi_isa_ischar(struct console *cp)
767*4ac2186dSToomas Soome {
768*4ac2186dSToomas Soome 	EFI_STATUS status;
769*4ac2186dSToomas Soome 	uint8_t control;
770*4ac2186dSToomas Soome 	struct serial *sp = cp->c_private;
771*4ac2186dSToomas Soome 
772*4ac2186dSToomas Soome 	/*
773*4ac2186dSToomas Soome 	 * if this device is also used as ConIn, some firmwares
774*4ac2186dSToomas Soome 	 * fail to return all input via SIO protocol.
775*4ac2186dSToomas Soome 	 */
776*4ac2186dSToomas Soome 	if (sp->is_efi_console) {
777*4ac2186dSToomas Soome 		return (efi_console.c_ready(&efi_console));
778*4ac2186dSToomas Soome 	}
779*4ac2186dSToomas Soome 
780*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Read(sp->io.isa,
781*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
782*4ac2186dSToomas Soome 	    sp->ioaddr + com_lsr, 1, &control);
783*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
784*4ac2186dSToomas Soome 		return (0);
785*4ac2186dSToomas Soome 
786*4ac2186dSToomas Soome 	return (control & LSR_RXRDY);
787*4ac2186dSToomas Soome }
788*4ac2186dSToomas Soome 
789*4ac2186dSToomas Soome static int
efi_isa_ioctl(struct console * cp __unused,int cmd __unused,void * data __unused)790*4ac2186dSToomas Soome efi_isa_ioctl(struct console *cp __unused, int cmd __unused,
791*4ac2186dSToomas Soome     void *data __unused)
792*4ac2186dSToomas Soome {
793*4ac2186dSToomas Soome 	return (ENOTTY);
794*4ac2186dSToomas Soome }
795*4ac2186dSToomas Soome 
796*4ac2186dSToomas Soome static void
efi_isa_devinfo(struct console * cp)797*4ac2186dSToomas Soome efi_isa_devinfo(struct console *cp)
798*4ac2186dSToomas Soome {
799*4ac2186dSToomas Soome 	struct serial *port = cp->c_private;
800*4ac2186dSToomas Soome 	EFI_DEVICE_PATH *dp;
801*4ac2186dSToomas Soome 	CHAR16 *text;
802*4ac2186dSToomas Soome 
803*4ac2186dSToomas Soome 	if (port->currdev != NULL) {
804*4ac2186dSToomas Soome 		dp = efi_lookup_devpath(port->currdev);
805*4ac2186dSToomas Soome 		if (dp == NULL)
806*4ac2186dSToomas Soome 			return;
807*4ac2186dSToomas Soome 
808*4ac2186dSToomas Soome 		text = efi_devpath_name(dp);
809*4ac2186dSToomas Soome 		if (text == NULL)
810*4ac2186dSToomas Soome 			return;
811*4ac2186dSToomas Soome 
812*4ac2186dSToomas Soome 		printf("\tISA IO device %S", text);
813*4ac2186dSToomas Soome 		efi_free_devpath_name(text);
814*4ac2186dSToomas Soome 		efi_close_devpath(port->currdev);
815*4ac2186dSToomas Soome 		return;
816*4ac2186dSToomas Soome 	}
817*4ac2186dSToomas Soome 
818*4ac2186dSToomas Soome 	if (port->ioaddr != 0) {
819*4ac2186dSToomas Soome 		printf("\tISA IO port %#x", port->ioaddr);
820*4ac2186dSToomas Soome 	}
821*4ac2186dSToomas Soome }
822*4ac2186dSToomas Soome 
823*4ac2186dSToomas Soome static char *
efi_isa_asprint_mode(struct serial * sp)824*4ac2186dSToomas Soome efi_isa_asprint_mode(struct serial *sp)
825*4ac2186dSToomas Soome {
826*4ac2186dSToomas Soome 	char par, *buf, *stop;
827*4ac2186dSToomas Soome 
828*4ac2186dSToomas Soome 	if (sp == NULL)
829*4ac2186dSToomas Soome 		return (NULL);
830*4ac2186dSToomas Soome 
831*4ac2186dSToomas Soome 	switch (sp->parity) {
832*4ac2186dSToomas Soome 	case NoParity:
833*4ac2186dSToomas Soome 		par = 'n';
834*4ac2186dSToomas Soome 		break;
835*4ac2186dSToomas Soome 	case EvenParity:
836*4ac2186dSToomas Soome 		par = 'e';
837*4ac2186dSToomas Soome 		break;
838*4ac2186dSToomas Soome 	case OddParity:
839*4ac2186dSToomas Soome 		par = 'o';
840*4ac2186dSToomas Soome 		break;
841*4ac2186dSToomas Soome 	case MarkParity:
842*4ac2186dSToomas Soome 		par = 'm';
843*4ac2186dSToomas Soome 		break;
844*4ac2186dSToomas Soome 	case SpaceParity:
845*4ac2186dSToomas Soome 		par = 's';
846*4ac2186dSToomas Soome 		break;
847*4ac2186dSToomas Soome 	default:
848*4ac2186dSToomas Soome 		par = 'n';
849*4ac2186dSToomas Soome 		break;
850*4ac2186dSToomas Soome 	}
851*4ac2186dSToomas Soome 
852*4ac2186dSToomas Soome 	switch (sp->stopbits) {
853*4ac2186dSToomas Soome 	case OneStopBit:
854*4ac2186dSToomas Soome 		stop = "1";
855*4ac2186dSToomas Soome 		break;
856*4ac2186dSToomas Soome 	case TwoStopBits:
857*4ac2186dSToomas Soome 		stop = "2";
858*4ac2186dSToomas Soome 		break;
859*4ac2186dSToomas Soome 	case OneFiveStopBits:
860*4ac2186dSToomas Soome 		stop = "1.5";
861*4ac2186dSToomas Soome 		break;
862*4ac2186dSToomas Soome 	default:
863*4ac2186dSToomas Soome 		stop = "1";
864*4ac2186dSToomas Soome 		break;
865*4ac2186dSToomas Soome 	}
866*4ac2186dSToomas Soome 
867*4ac2186dSToomas Soome 	(void) asprintf(&buf, "%ju,%d,%c,%s,-", sp->baudrate,
868*4ac2186dSToomas Soome 	    sp->databits, par, stop);
869*4ac2186dSToomas Soome 	return (buf);
870*4ac2186dSToomas Soome }
871*4ac2186dSToomas Soome 
872*4ac2186dSToomas Soome static int
efi_isa_parse_mode(struct serial * sp,const char * value)873*4ac2186dSToomas Soome efi_isa_parse_mode(struct serial *sp, const char *value)
874*4ac2186dSToomas Soome {
875*4ac2186dSToomas Soome 	unsigned long n;
876*4ac2186dSToomas Soome 	uint64_t baudrate;
877*4ac2186dSToomas Soome 	uint8_t databits;
878*4ac2186dSToomas Soome 	EFI_PARITY_TYPE parity;
879*4ac2186dSToomas Soome 	EFI_STOP_BITS_TYPE stopbits;
880*4ac2186dSToomas Soome 	char *ep;
881*4ac2186dSToomas Soome 
882*4ac2186dSToomas Soome 	if (value == NULL || *value == '\0')
883*4ac2186dSToomas Soome 		return (CMD_ERROR);
884*4ac2186dSToomas Soome 
885*4ac2186dSToomas Soome 	errno = 0;
886*4ac2186dSToomas Soome 	n = strtoul(value, &ep, 10);
887*4ac2186dSToomas Soome 	if (errno != 0 || *ep != ',')
888*4ac2186dSToomas Soome 		return (CMD_ERROR);
889*4ac2186dSToomas Soome 	baudrate = n;
890*4ac2186dSToomas Soome 
891*4ac2186dSToomas Soome 	ep++;
892*4ac2186dSToomas Soome 	n = strtoul(ep, &ep, 10);
893*4ac2186dSToomas Soome 	if (errno != 0 || *ep != ',')
894*4ac2186dSToomas Soome 		return (CMD_ERROR);
895*4ac2186dSToomas Soome 
896*4ac2186dSToomas Soome 	switch (n) {
897*4ac2186dSToomas Soome 	case 5:
898*4ac2186dSToomas Soome 		databits = 5;
899*4ac2186dSToomas Soome 		break;
900*4ac2186dSToomas Soome 	case 6:
901*4ac2186dSToomas Soome 		databits = 6;
902*4ac2186dSToomas Soome 		break;
903*4ac2186dSToomas Soome 	case 7:
904*4ac2186dSToomas Soome 		databits = 7;
905*4ac2186dSToomas Soome 		break;
906*4ac2186dSToomas Soome 	case 8:
907*4ac2186dSToomas Soome 		databits = 8;
908*4ac2186dSToomas Soome 		break;
909*4ac2186dSToomas Soome 	default:
910*4ac2186dSToomas Soome 		return (CMD_ERROR);
911*4ac2186dSToomas Soome 	}
912*4ac2186dSToomas Soome 
913*4ac2186dSToomas Soome 	ep++;
914*4ac2186dSToomas Soome 	switch (*ep++) {
915*4ac2186dSToomas Soome 	case 'n':
916*4ac2186dSToomas Soome 		parity = NoParity;
917*4ac2186dSToomas Soome 		break;
918*4ac2186dSToomas Soome 	case 'e':
919*4ac2186dSToomas Soome 		parity = EvenParity;
920*4ac2186dSToomas Soome 		break;
921*4ac2186dSToomas Soome 	case 'o':
922*4ac2186dSToomas Soome 		parity = OddParity;
923*4ac2186dSToomas Soome 		break;
924*4ac2186dSToomas Soome 	default:
925*4ac2186dSToomas Soome 		return (CMD_ERROR);
926*4ac2186dSToomas Soome 	}
927*4ac2186dSToomas Soome 
928*4ac2186dSToomas Soome 	if (*ep == ',')
929*4ac2186dSToomas Soome 		ep++;
930*4ac2186dSToomas Soome 	else
931*4ac2186dSToomas Soome 		return (CMD_ERROR);
932*4ac2186dSToomas Soome 
933*4ac2186dSToomas Soome 	switch (*ep++) {
934*4ac2186dSToomas Soome 	case '1':
935*4ac2186dSToomas Soome 		stopbits = OneStopBit;
936*4ac2186dSToomas Soome 		break;
937*4ac2186dSToomas Soome 	case '2':
938*4ac2186dSToomas Soome 		stopbits = TwoStopBits;
939*4ac2186dSToomas Soome 		break;
940*4ac2186dSToomas Soome 	default:
941*4ac2186dSToomas Soome 		return (CMD_ERROR);
942*4ac2186dSToomas Soome 	}
943*4ac2186dSToomas Soome 
944*4ac2186dSToomas Soome 	/* handshake is ignored, but we check syntax anyhow */
945*4ac2186dSToomas Soome 	if (*ep == ',')
946*4ac2186dSToomas Soome 		ep++;
947*4ac2186dSToomas Soome 	else
948*4ac2186dSToomas Soome 		return (CMD_ERROR);
949*4ac2186dSToomas Soome 
950*4ac2186dSToomas Soome 	switch (*ep++) {
951*4ac2186dSToomas Soome 	case '-':
952*4ac2186dSToomas Soome 	case 'h':
953*4ac2186dSToomas Soome 	case 's':
954*4ac2186dSToomas Soome 		break;
955*4ac2186dSToomas Soome 	default:
956*4ac2186dSToomas Soome 		return (CMD_ERROR);
957*4ac2186dSToomas Soome 	}
958*4ac2186dSToomas Soome 
959*4ac2186dSToomas Soome 	if (*ep != '\0')
960*4ac2186dSToomas Soome 		return (CMD_ERROR);
961*4ac2186dSToomas Soome 
962*4ac2186dSToomas Soome 	sp->baudrate = baudrate;
963*4ac2186dSToomas Soome 	sp->databits = databits;
964*4ac2186dSToomas Soome 	sp->parity = parity;
965*4ac2186dSToomas Soome 	sp->stopbits = stopbits;
966*4ac2186dSToomas Soome 	return (CMD_OK);
967*4ac2186dSToomas Soome }
968*4ac2186dSToomas Soome 
969*4ac2186dSToomas Soome /*
970*4ac2186dSToomas Soome  * CMD_ERROR will cause set/setenv/setprop command to fail,
971*4ac2186dSToomas Soome  * when used in loader scripts (forth), this will cause processing
972*4ac2186dSToomas Soome  * of boot scripts to fail, rendering bootloading impossible.
973*4ac2186dSToomas Soome  * To prevent such unfortunate situation, we return CMD_OK when
974*4ac2186dSToomas Soome  * there is no such port, or there is invalid value in mode line.
975*4ac2186dSToomas Soome  */
976*4ac2186dSToomas Soome static int
efi_isa_mode_set(struct env_var * ev,int flags,const void * value)977*4ac2186dSToomas Soome efi_isa_mode_set(struct env_var *ev, int flags, const void *value)
978*4ac2186dSToomas Soome {
979*4ac2186dSToomas Soome 	struct console *cp;
980*4ac2186dSToomas Soome 	char name[15];
981*4ac2186dSToomas Soome 
982*4ac2186dSToomas Soome 	if (value == NULL)
983*4ac2186dSToomas Soome 		return (CMD_ERROR);
984*4ac2186dSToomas Soome 
985*4ac2186dSToomas Soome 	if ((cp = cons_get_console(ev->ev_name)) == NULL)
986*4ac2186dSToomas Soome 		return (CMD_OK);
987*4ac2186dSToomas Soome 
988*4ac2186dSToomas Soome 	/* Do not override serial setup if port is listed in ConIn */
989*4ac2186dSToomas Soome 	(void) snprintf(name, sizeof (name), "%s-spcr-mode", cp->c_name);
990*4ac2186dSToomas Soome 	if (getenv(name) == NULL) {
991*4ac2186dSToomas Soome 		if (efi_isa_parse_mode(cp->c_private, value) == CMD_ERROR) {
992*4ac2186dSToomas Soome 			printf("%s: invalid mode: %s\n", ev->ev_name,
993*4ac2186dSToomas Soome 			    (char *)value);
994*4ac2186dSToomas Soome 			return (CMD_OK);
995*4ac2186dSToomas Soome 		}
996*4ac2186dSToomas Soome 
997*4ac2186dSToomas Soome 		(void) efi_isa_setup(cp);
998*4ac2186dSToomas Soome 		(void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value,
999*4ac2186dSToomas Soome 		    NULL, NULL);
1000*4ac2186dSToomas Soome 	}
1001*4ac2186dSToomas Soome 
1002*4ac2186dSToomas Soome 	return (CMD_OK);
1003*4ac2186dSToomas Soome }
1004*4ac2186dSToomas Soome 
1005*4ac2186dSToomas Soome /*
1006*4ac2186dSToomas Soome  * CMD_ERROR will cause set/setenv/setprop command to fail,
1007*4ac2186dSToomas Soome  * when used in loader scripts (forth), this will cause processing
1008*4ac2186dSToomas Soome  * of boot scripts to fail, rendering bootloading impossible.
1009*4ac2186dSToomas Soome  * To prevent such unfortunate situation, we return CMD_OK when
1010*4ac2186dSToomas Soome  * there is no such port or invalid value was used.
1011*4ac2186dSToomas Soome  */
1012*4ac2186dSToomas Soome static int
efi_isa_cd_set(struct env_var * ev,int flags,const void * value)1013*4ac2186dSToomas Soome efi_isa_cd_set(struct env_var *ev, int flags, const void *value)
1014*4ac2186dSToomas Soome {
1015*4ac2186dSToomas Soome 	struct console *cp;
1016*4ac2186dSToomas Soome 	struct serial *sp;
1017*4ac2186dSToomas Soome 
1018*4ac2186dSToomas Soome 	if (value == NULL)
1019*4ac2186dSToomas Soome 		return (CMD_OK);
1020*4ac2186dSToomas Soome 
1021*4ac2186dSToomas Soome 	if ((cp = cons_get_console(ev->ev_name)) == NULL)
1022*4ac2186dSToomas Soome 		return (CMD_OK);
1023*4ac2186dSToomas Soome 
1024*4ac2186dSToomas Soome 	sp = cp->c_private;
1025*4ac2186dSToomas Soome 	if (strcmp(value, "true") == 0) {
1026*4ac2186dSToomas Soome 		sp->ignore_cd = 1;
1027*4ac2186dSToomas Soome 	} else if (strcmp(value, "false") == 0) {
1028*4ac2186dSToomas Soome 		sp->ignore_cd = 0;
1029*4ac2186dSToomas Soome 	} else {
1030*4ac2186dSToomas Soome 		printf("%s: invalid value: %s\n", ev->ev_name,
1031*4ac2186dSToomas Soome 		    (char *)value);
1032*4ac2186dSToomas Soome 		return (CMD_OK);
1033*4ac2186dSToomas Soome 	}
1034*4ac2186dSToomas Soome 
1035*4ac2186dSToomas Soome 	(void) efi_isa_setup(cp);
1036*4ac2186dSToomas Soome 
1037*4ac2186dSToomas Soome 	(void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
1038*4ac2186dSToomas Soome 
1039*4ac2186dSToomas Soome 	return (CMD_OK);
1040*4ac2186dSToomas Soome }
1041*4ac2186dSToomas Soome 
1042*4ac2186dSToomas Soome /*
1043*4ac2186dSToomas Soome  * CMD_ERROR will cause set/setenv/setprop command to fail,
1044*4ac2186dSToomas Soome  * when used in loader scripts (forth), this will cause processing
1045*4ac2186dSToomas Soome  * of boot scripts to fail, rendering bootloading impossible.
1046*4ac2186dSToomas Soome  * To prevent such unfortunate situation, we return CMD_OK when
1047*4ac2186dSToomas Soome  * there is no such port, or invalid value was used.
1048*4ac2186dSToomas Soome  */
1049*4ac2186dSToomas Soome static int
efi_isa_rtsdtr_set(struct env_var * ev,int flags,const void * value)1050*4ac2186dSToomas Soome efi_isa_rtsdtr_set(struct env_var *ev, int flags, const void *value)
1051*4ac2186dSToomas Soome {
1052*4ac2186dSToomas Soome 	struct console *cp;
1053*4ac2186dSToomas Soome 	struct serial *sp;
1054*4ac2186dSToomas Soome 
1055*4ac2186dSToomas Soome 	if (value == NULL)
1056*4ac2186dSToomas Soome 		return (CMD_OK);
1057*4ac2186dSToomas Soome 
1058*4ac2186dSToomas Soome 	if ((cp = cons_get_console(ev->ev_name)) == NULL)
1059*4ac2186dSToomas Soome 		return (CMD_OK);
1060*4ac2186dSToomas Soome 
1061*4ac2186dSToomas Soome 	sp = cp->c_private;
1062*4ac2186dSToomas Soome 	if (strcmp(value, "true") == 0) {
1063*4ac2186dSToomas Soome 		sp->rtsdtr_off = 1;
1064*4ac2186dSToomas Soome 	} else if (strcmp(value, "false") == 0) {
1065*4ac2186dSToomas Soome 		sp->rtsdtr_off = 0;
1066*4ac2186dSToomas Soome 	} else {
1067*4ac2186dSToomas Soome 		printf("%s: invalid value: %s\n", ev->ev_name,
1068*4ac2186dSToomas Soome 		    (char *)value);
1069*4ac2186dSToomas Soome 		return (CMD_OK);
1070*4ac2186dSToomas Soome 	}
1071*4ac2186dSToomas Soome 
1072*4ac2186dSToomas Soome 	(void) efi_isa_setup(cp);
1073*4ac2186dSToomas Soome 
1074*4ac2186dSToomas Soome 	(void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
1075*4ac2186dSToomas Soome 
1076*4ac2186dSToomas Soome 	return (CMD_OK);
1077*4ac2186dSToomas Soome }
1078*4ac2186dSToomas Soome 
1079*4ac2186dSToomas Soome /*
1080*4ac2186dSToomas Soome  * In case of error, we also reset ACTIVE flags, so the console
1081*4ac2186dSToomas Soome  * framefork will try alternate consoles.
1082*4ac2186dSToomas Soome  */
1083*4ac2186dSToomas Soome static bool
efi_isa_setup(struct console * cp)1084*4ac2186dSToomas Soome efi_isa_setup(struct console *cp)
1085*4ac2186dSToomas Soome {
1086*4ac2186dSToomas Soome 	EFI_STATUS status;
1087*4ac2186dSToomas Soome 	uint8_t data, lcr;
1088*4ac2186dSToomas Soome 	struct serial *sp = cp->c_private;
1089*4ac2186dSToomas Soome 	uint_t tries, try_count = 1000000;
1090*4ac2186dSToomas Soome 
1091*4ac2186dSToomas Soome 	if (sp->baudrate == 0)
1092*4ac2186dSToomas Soome 		return (false);
1093*4ac2186dSToomas Soome 
1094*4ac2186dSToomas Soome 	switch (sp->databits) {
1095*4ac2186dSToomas Soome 	case 8:
1096*4ac2186dSToomas Soome 		lcr = BITS8;
1097*4ac2186dSToomas Soome 		break;
1098*4ac2186dSToomas Soome 	case 7:
1099*4ac2186dSToomas Soome 		lcr = BITS7;
1100*4ac2186dSToomas Soome 		break;
1101*4ac2186dSToomas Soome 	case 6:
1102*4ac2186dSToomas Soome 		lcr = BITS6;
1103*4ac2186dSToomas Soome 		break;
1104*4ac2186dSToomas Soome 	case 5:
1105*4ac2186dSToomas Soome 		lcr = BITS5;
1106*4ac2186dSToomas Soome 		break;
1107*4ac2186dSToomas Soome 	default:
1108*4ac2186dSToomas Soome 		lcr = BITS8;
1109*4ac2186dSToomas Soome 		break;
1110*4ac2186dSToomas Soome 	}
1111*4ac2186dSToomas Soome 
1112*4ac2186dSToomas Soome 	switch (sp->parity) {
1113*4ac2186dSToomas Soome 	case NoParity:
1114*4ac2186dSToomas Soome 		break;
1115*4ac2186dSToomas Soome 	case OddParity:
1116*4ac2186dSToomas Soome 		lcr |= PAREN|PARODD;
1117*4ac2186dSToomas Soome 		break;
1118*4ac2186dSToomas Soome 	case EvenParity:
1119*4ac2186dSToomas Soome 		lcr |= PAREN|PAREVN;
1120*4ac2186dSToomas Soome 		break;
1121*4ac2186dSToomas Soome 	default:
1122*4ac2186dSToomas Soome 		break;
1123*4ac2186dSToomas Soome 	}
1124*4ac2186dSToomas Soome 
1125*4ac2186dSToomas Soome 	switch (sp->stopbits) {
1126*4ac2186dSToomas Soome 	case OneStopBit:
1127*4ac2186dSToomas Soome 		break;
1128*4ac2186dSToomas Soome 	case TwoStopBits:
1129*4ac2186dSToomas Soome 		lcr |= STOP2;
1130*4ac2186dSToomas Soome 		break;
1131*4ac2186dSToomas Soome 	default:
1132*4ac2186dSToomas Soome 		break;
1133*4ac2186dSToomas Soome 	}
1134*4ac2186dSToomas Soome 
1135*4ac2186dSToomas Soome 	data = CFCR_DLAB | lcr;
1136*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Write(sp->io.isa,
1137*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1138*4ac2186dSToomas Soome 	    sp->ioaddr + com_cfcr, 1, &data);
1139*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
1140*4ac2186dSToomas Soome 		return (false);
1141*4ac2186dSToomas Soome 	data = COMC_BPS(sp->baudrate) & 0xff;
1142*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Write(sp->io.isa,
1143*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1144*4ac2186dSToomas Soome 	    sp->ioaddr + com_dlbl, 1, &data);
1145*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
1146*4ac2186dSToomas Soome 		return (false);
1147*4ac2186dSToomas Soome 	data = COMC_BPS(sp->baudrate) >> 8;
1148*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Write(sp->io.isa,
1149*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1150*4ac2186dSToomas Soome 	    sp->ioaddr + com_dlbh, 1, &data);
1151*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
1152*4ac2186dSToomas Soome 		return (false);
1153*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Write(sp->io.isa,
1154*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1155*4ac2186dSToomas Soome 	    sp->ioaddr + com_cfcr, 1, &lcr);
1156*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
1157*4ac2186dSToomas Soome 		return (false);
1158*4ac2186dSToomas Soome 	data = sp->rtsdtr_off? ~(MCR_RTS | MCR_DTR) : MCR_RTS | MCR_DTR;
1159*4ac2186dSToomas Soome 	status = sp->io.isa->Io.Write(sp->io.isa,
1160*4ac2186dSToomas Soome 	    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1161*4ac2186dSToomas Soome 	    sp->ioaddr + com_mcr, 1, &data);
1162*4ac2186dSToomas Soome 	if (EFI_ERROR(status))
1163*4ac2186dSToomas Soome 		return (false);
1164*4ac2186dSToomas Soome 
1165*4ac2186dSToomas Soome 	tries = 0;
1166*4ac2186dSToomas Soome 	do {
1167*4ac2186dSToomas Soome 		status = sp->io.isa->Io.Read(sp->io.isa,
1168*4ac2186dSToomas Soome 		    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1169*4ac2186dSToomas Soome 		    sp->ioaddr + com_data, 1, &data);
1170*4ac2186dSToomas Soome 		status = sp->io.isa->Io.Read(sp->io.isa,
1171*4ac2186dSToomas Soome 		    EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT,
1172*4ac2186dSToomas Soome 		    sp->ioaddr + com_lsr, 1, &data);
1173*4ac2186dSToomas Soome 	} while (data & LSR_RXRDY && ++tries < try_count);
1174*4ac2186dSToomas Soome 
1175*4ac2186dSToomas Soome 	if (tries == try_count)
1176*4ac2186dSToomas Soome 		return (false);
1177*4ac2186dSToomas Soome 
1178*4ac2186dSToomas Soome 	/* Mark this port usable. */
1179*4ac2186dSToomas Soome 	cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
1180*4ac2186dSToomas Soome 	return (true);
1181*4ac2186dSToomas Soome }
1182