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