130c75cb0SToomas Soome /*
230c75cb0SToomas Soome * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
330c75cb0SToomas Soome *
430c75cb0SToomas Soome * Redistribution and use in source and binary forms, with or without
530c75cb0SToomas Soome * modification, are permitted provided that the following conditions
630c75cb0SToomas Soome * are met:
730c75cb0SToomas Soome * 1. Redistributions of source code must retain the above copyright
830c75cb0SToomas Soome * notice, this list of conditions and the following disclaimer.
930c75cb0SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
1030c75cb0SToomas Soome * notice, this list of conditions and the following disclaimer in the
1130c75cb0SToomas Soome * documentation and/or other materials provided with the distribution.
1230c75cb0SToomas Soome *
1330c75cb0SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1430c75cb0SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1530c75cb0SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1630c75cb0SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1730c75cb0SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1830c75cb0SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1930c75cb0SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2030c75cb0SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2130c75cb0SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2230c75cb0SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2330c75cb0SToomas Soome * SUCH DAMAGE.
2430c75cb0SToomas Soome */
2530c75cb0SToomas Soome
265ac07b12SToomas Soome /*
275ac07b12SToomas Soome * We do not use this implementation with x86 till we can fix two issues:
285ac07b12SToomas Soome * 1. Reliably identify the serial ports in correct order.
295ac07b12SToomas Soome * 2. Ensure we get properly working reads from serial io.
305ac07b12SToomas Soome */
315ac07b12SToomas Soome
3230c75cb0SToomas Soome #include <sys/cdefs.h>
3330c75cb0SToomas Soome
3430c75cb0SToomas Soome #include <stand.h>
3530c75cb0SToomas Soome #include <sys/errno.h>
3630c75cb0SToomas Soome #include <bootstrap.h>
37fec53dd4SToomas Soome #include <stdbool.h>
3830c75cb0SToomas Soome
3930c75cb0SToomas Soome #include <efi.h>
4030c75cb0SToomas Soome #include <efilib.h>
41*f334afcfSToomas Soome #include <Protocol/SerialIo.h>
4230c75cb0SToomas Soome
4330c75cb0SToomas Soome #include "loader_efi.h"
4430c75cb0SToomas Soome
45*f334afcfSToomas Soome EFI_GUID gEfiSerialIoProtocolGuid = EFI_SERIAL_IO_PROTOCOL_GUID;
46*f334afcfSToomas Soome EFI_GUID gEfiSerialTerminalDeviceTypeGuid =
47*f334afcfSToomas Soome EFI_SERIAL_TERMINAL_DEVICE_TYPE_GUID;
4830c75cb0SToomas Soome
4930c75cb0SToomas Soome #define COMC_TXWAIT 0x40000 /* transmit timeout */
5030c75cb0SToomas Soome
5130c75cb0SToomas Soome #ifndef COMSPEED
5230c75cb0SToomas Soome #define COMSPEED 9600
5330c75cb0SToomas Soome #endif
5430c75cb0SToomas Soome
55a2f10c44SToomas Soome #define PNP0501 0x501 /* 16550A-compatible COM port */
56a2f10c44SToomas Soome
5730c75cb0SToomas Soome struct serial {
5830c75cb0SToomas Soome uint64_t baudrate;
5930c75cb0SToomas Soome uint8_t databits;
6030c75cb0SToomas Soome EFI_PARITY_TYPE parity;
6130c75cb0SToomas Soome EFI_STOP_BITS_TYPE stopbits;
6230c75cb0SToomas Soome uint8_t ignore_cd; /* boolean */
6330c75cb0SToomas Soome uint8_t rtsdtr_off; /* boolean */
6430c75cb0SToomas Soome int ioaddr; /* index in handles array */
6530c75cb0SToomas Soome SERIAL_IO_INTERFACE *sio;
6630c75cb0SToomas Soome };
6730c75cb0SToomas Soome
6830c75cb0SToomas Soome static void comc_probe(struct console *);
6930c75cb0SToomas Soome static int comc_init(struct console *, int);
7030c75cb0SToomas Soome static void comc_putchar(struct console *, int);
7130c75cb0SToomas Soome static int comc_getchar(struct console *);
7230c75cb0SToomas Soome static int comc_ischar(struct console *);
739890ff83SToomas Soome static int comc_ioctl(struct console *, int, void *);
7480e47917SToomas Soome static void comc_devinfo(struct console *);
75fec53dd4SToomas Soome static bool comc_setup(struct console *);
7630c75cb0SToomas Soome static char *comc_asprint_mode(struct serial *);
7730c75cb0SToomas Soome static int comc_parse_mode(struct serial *, const char *);
7830c75cb0SToomas Soome static int comc_mode_set(struct env_var *, int, const void *);
7930c75cb0SToomas Soome static int comc_cd_set(struct env_var *, int, const void *);
8030c75cb0SToomas Soome static int comc_rtsdtr_set(struct env_var *, int, const void *);
8130c75cb0SToomas Soome
8230c75cb0SToomas Soome struct console ttya = {
8330c75cb0SToomas Soome .c_name = "ttya",
8430c75cb0SToomas Soome .c_desc = "serial port a",
8530c75cb0SToomas Soome .c_flags = 0,
8630c75cb0SToomas Soome .c_probe = comc_probe,
8730c75cb0SToomas Soome .c_init = comc_init,
8830c75cb0SToomas Soome .c_out = comc_putchar,
8930c75cb0SToomas Soome .c_in = comc_getchar,
9030c75cb0SToomas Soome .c_ready = comc_ischar,
919890ff83SToomas Soome .c_ioctl = comc_ioctl,
9280e47917SToomas Soome .c_devinfo = comc_devinfo,
9330c75cb0SToomas Soome .c_private = NULL
9430c75cb0SToomas Soome };
9530c75cb0SToomas Soome
9630c75cb0SToomas Soome struct console ttyb = {
9730c75cb0SToomas Soome .c_name = "ttyb",
9830c75cb0SToomas Soome .c_desc = "serial port b",
9930c75cb0SToomas Soome .c_flags = 0,
10030c75cb0SToomas Soome .c_probe = comc_probe,
10130c75cb0SToomas Soome .c_init = comc_init,
10230c75cb0SToomas Soome .c_out = comc_putchar,
10330c75cb0SToomas Soome .c_in = comc_getchar,
10430c75cb0SToomas Soome .c_ready = comc_ischar,
1059890ff83SToomas Soome .c_ioctl = comc_ioctl,
10680e47917SToomas Soome .c_devinfo = comc_devinfo,
10730c75cb0SToomas Soome .c_private = NULL
10830c75cb0SToomas Soome };
10930c75cb0SToomas Soome
11030c75cb0SToomas Soome struct console ttyc = {
11130c75cb0SToomas Soome .c_name = "ttyc",
11230c75cb0SToomas Soome .c_desc = "serial port c",
11330c75cb0SToomas Soome .c_flags = 0,
11430c75cb0SToomas Soome .c_probe = comc_probe,
11530c75cb0SToomas Soome .c_init = comc_init,
11630c75cb0SToomas Soome .c_out = comc_putchar,
11730c75cb0SToomas Soome .c_in = comc_getchar,
11830c75cb0SToomas Soome .c_ready = comc_ischar,
1199890ff83SToomas Soome .c_ioctl = comc_ioctl,
12080e47917SToomas Soome .c_devinfo = comc_devinfo,
12130c75cb0SToomas Soome .c_private = NULL
12230c75cb0SToomas Soome };
12330c75cb0SToomas Soome
12430c75cb0SToomas Soome struct console ttyd = {
12530c75cb0SToomas Soome .c_name = "ttyd",
12630c75cb0SToomas Soome .c_desc = "serial port d",
12730c75cb0SToomas Soome .c_flags = 0,
12830c75cb0SToomas Soome .c_probe = comc_probe,
12930c75cb0SToomas Soome .c_init = comc_init,
13030c75cb0SToomas Soome .c_out = comc_putchar,
13130c75cb0SToomas Soome .c_in = comc_getchar,
13230c75cb0SToomas Soome .c_ready = comc_ischar,
1339890ff83SToomas Soome .c_ioctl = comc_ioctl,
13480e47917SToomas Soome .c_devinfo = comc_devinfo,
13530c75cb0SToomas Soome .c_private = NULL
13630c75cb0SToomas Soome };
13730c75cb0SToomas Soome
138a2f10c44SToomas Soome /*
139a2f10c44SToomas Soome * Find serial device number from device path.
140a2f10c44SToomas Soome * Return -1 if not found.
141a2f10c44SToomas Soome */
142a2f10c44SToomas Soome static int
efi_serial_get_index(EFI_DEVICE_PATH * devpath)143a2f10c44SToomas Soome efi_serial_get_index(EFI_DEVICE_PATH *devpath)
144a2f10c44SToomas Soome {
145a2f10c44SToomas Soome ACPI_HID_DEVICE_PATH *acpi;
146a2f10c44SToomas Soome
147a2f10c44SToomas Soome while (!IsDevicePathEnd(devpath)) {
148a2f10c44SToomas Soome if (DevicePathType(devpath) == ACPI_DEVICE_PATH &&
149a2f10c44SToomas Soome DevicePathSubType(devpath) == ACPI_DP) {
150a2f10c44SToomas Soome
151a2f10c44SToomas Soome acpi = (ACPI_HID_DEVICE_PATH *)devpath;
152a2f10c44SToomas Soome if (acpi->HID == EISA_PNP_ID(PNP0501)) {
153a2f10c44SToomas Soome return (acpi->UID);
154a2f10c44SToomas Soome }
155a2f10c44SToomas Soome }
156a2f10c44SToomas Soome
157a2f10c44SToomas Soome devpath = NextDevicePathNode(devpath);
158a2f10c44SToomas Soome }
159a2f10c44SToomas Soome return (-1);
160a2f10c44SToomas Soome }
161a2f10c44SToomas Soome
162a2f10c44SToomas Soome /*
163a2f10c44SToomas Soome * The order of handles from LocateHandle() is not known, we need to
164a2f10c44SToomas Soome * iterate handles, pick device path for handle, and check the device
165a2f10c44SToomas Soome * number.
166a2f10c44SToomas Soome */
167a2f10c44SToomas Soome static EFI_HANDLE
efi_serial_get_handle(int port)168a2f10c44SToomas Soome efi_serial_get_handle(int port)
169a2f10c44SToomas Soome {
170a2f10c44SToomas Soome EFI_STATUS status;
171a2f10c44SToomas Soome EFI_HANDLE *handles, handle;
172a2f10c44SToomas Soome EFI_DEVICE_PATH *devpath;
17369764de3SToomas Soome uint_t index, nhandles;
174a2f10c44SToomas Soome
175a2f10c44SToomas Soome if (port == -1)
176a2f10c44SToomas Soome return (NULL);
177a2f10c44SToomas Soome
178*f334afcfSToomas Soome status = efi_get_protocol_handles(&gEfiSerialIoProtocolGuid,
179*f334afcfSToomas Soome &nhandles, &handles);
180a2f10c44SToomas Soome if (EFI_ERROR(status))
181a2f10c44SToomas Soome return (NULL);
182a2f10c44SToomas Soome
183a2f10c44SToomas Soome handle = NULL;
184a2f10c44SToomas Soome for (index = 0; index < nhandles; index++) {
185a2f10c44SToomas Soome devpath = efi_lookup_devpath(handles[index]);
186a2f10c44SToomas Soome if (port == efi_serial_get_index(devpath)) {
187a2f10c44SToomas Soome handle = (handles[index]);
188a2f10c44SToomas Soome break;
189a2f10c44SToomas Soome }
190a2f10c44SToomas Soome }
191a2f10c44SToomas Soome
192a2f10c44SToomas Soome /*
193a2f10c44SToomas Soome * In case we did fail to identify the device by path, use port as
194a2f10c44SToomas Soome * array index. Note, we did check port == -1 above.
195a2f10c44SToomas Soome */
196a2f10c44SToomas Soome if (port < nhandles && handle == NULL)
197a2f10c44SToomas Soome handle = handles[port];
198a2f10c44SToomas Soome
199a2f10c44SToomas Soome free(handles);
200a2f10c44SToomas Soome return (handle);
201a2f10c44SToomas Soome }
202a2f10c44SToomas Soome
20330c75cb0SToomas Soome static void
comc_probe(struct console * cp)20430c75cb0SToomas Soome comc_probe(struct console *cp)
20530c75cb0SToomas Soome {
20630c75cb0SToomas Soome EFI_STATUS status;
207a2f10c44SToomas Soome EFI_HANDLE handle;
20830c75cb0SToomas Soome struct serial *port;
20930c75cb0SToomas Soome char name[20];
21030c75cb0SToomas Soome char value[20];
211dd842a53SToomas Soome char *env;
21230c75cb0SToomas Soome
21330c75cb0SToomas Soome /* are we already set up? */
21430c75cb0SToomas Soome if (cp->c_private != NULL)
21530c75cb0SToomas Soome return;
21630c75cb0SToomas Soome
21730c75cb0SToomas Soome cp->c_private = malloc(sizeof (struct serial));
21830c75cb0SToomas Soome port = cp->c_private;
21930c75cb0SToomas Soome port->baudrate = COMSPEED;
22030c75cb0SToomas Soome
221a2f10c44SToomas Soome port->ioaddr = -1; /* invalid port */
22230c75cb0SToomas Soome if (strcmp(cp->c_name, "ttya") == 0)
22330c75cb0SToomas Soome port->ioaddr = 0;
22430c75cb0SToomas Soome else if (strcmp(cp->c_name, "ttyb") == 0)
22530c75cb0SToomas Soome port->ioaddr = 1;
22630c75cb0SToomas Soome else if (strcmp(cp->c_name, "ttyc") == 0)
22730c75cb0SToomas Soome port->ioaddr = 2;
22830c75cb0SToomas Soome else if (strcmp(cp->c_name, "ttyd") == 0)
22930c75cb0SToomas Soome port->ioaddr = 3;
23030c75cb0SToomas Soome
23130c75cb0SToomas Soome port->databits = 8; /* 8,n,1 */
23230c75cb0SToomas Soome port->parity = NoParity; /* 8,n,1 */
23330c75cb0SToomas Soome port->stopbits = OneStopBit; /* 8,n,1 */
23430c75cb0SToomas Soome port->ignore_cd = 1; /* ignore cd */
23530c75cb0SToomas Soome port->rtsdtr_off = 0; /* rts-dtr is on */
23630c75cb0SToomas Soome port->sio = NULL;
23730c75cb0SToomas Soome
238a2f10c44SToomas Soome handle = efi_serial_get_handle(port->ioaddr);
239a2f10c44SToomas Soome
240a2f10c44SToomas Soome if (handle != NULL) {
241*f334afcfSToomas Soome status = BS->OpenProtocol(handle, &gEfiSerialIoProtocolGuid,
242a2f10c44SToomas Soome (void**)&port->sio, IH, NULL,
24330c75cb0SToomas Soome EFI_OPEN_PROTOCOL_GET_PROTOCOL);
24430c75cb0SToomas Soome
24530c75cb0SToomas Soome if (EFI_ERROR(status))
246a2f10c44SToomas Soome port->sio = NULL;
24730c75cb0SToomas Soome }
24830c75cb0SToomas Soome
24930c75cb0SToomas Soome snprintf(name, sizeof (name), "%s-mode", cp->c_name);
25030c75cb0SToomas Soome env = getenv(name);
25130c75cb0SToomas Soome
25230c75cb0SToomas Soome if (env != NULL)
25330c75cb0SToomas Soome (void) comc_parse_mode(port, env);
25430c75cb0SToomas Soome
25530c75cb0SToomas Soome env = comc_asprint_mode(port);
25630c75cb0SToomas Soome
25730c75cb0SToomas Soome if (env != NULL) {
25830c75cb0SToomas Soome unsetenv(name);
25930c75cb0SToomas Soome env_setenv(name, EV_VOLATILE, env, comc_mode_set, env_nounset);
26030c75cb0SToomas Soome free(env);
26130c75cb0SToomas Soome }
26230c75cb0SToomas Soome
26330c75cb0SToomas Soome snprintf(name, sizeof (name), "%s-ignore-cd", cp->c_name);
26430c75cb0SToomas Soome env = getenv(name);
26530c75cb0SToomas Soome if (env != NULL) {
26630c75cb0SToomas Soome if (strcmp(env, "true") == 0)
26730c75cb0SToomas Soome port->ignore_cd = 1;
26830c75cb0SToomas Soome else if (strcmp(env, "false") == 0)
26930c75cb0SToomas Soome port->ignore_cd = 0;
27030c75cb0SToomas Soome }
27130c75cb0SToomas Soome
27230c75cb0SToomas Soome snprintf(value, sizeof (value), "%s",
27330c75cb0SToomas Soome port->ignore_cd? "true" : "false");
27430c75cb0SToomas Soome unsetenv(name);
27530c75cb0SToomas Soome env_setenv(name, EV_VOLATILE, value, comc_cd_set, env_nounset);
27630c75cb0SToomas Soome
27730c75cb0SToomas Soome snprintf(name, sizeof (name), "%s-rts-dtr-off", cp->c_name);
27830c75cb0SToomas Soome env = getenv(name);
27930c75cb0SToomas Soome if (env != NULL) {
28030c75cb0SToomas Soome if (strcmp(env, "true") == 0)
28130c75cb0SToomas Soome port->rtsdtr_off = 1;
28230c75cb0SToomas Soome else if (strcmp(env, "false") == 0)
28330c75cb0SToomas Soome port->rtsdtr_off = 0;
28430c75cb0SToomas Soome }
28530c75cb0SToomas Soome
28630c75cb0SToomas Soome snprintf(value, sizeof (value), "%s",
28730c75cb0SToomas Soome port->rtsdtr_off? "true" : "false");
28830c75cb0SToomas Soome unsetenv(name);
28930c75cb0SToomas Soome env_setenv(name, EV_VOLATILE, value, comc_rtsdtr_set, env_nounset);
290fec53dd4SToomas Soome
291fec53dd4SToomas Soome cp->c_flags = 0;
292fec53dd4SToomas Soome if (comc_setup(cp))
293fec53dd4SToomas Soome cp->c_flags = C_PRESENTIN | C_PRESENTOUT;
29430c75cb0SToomas Soome }
29530c75cb0SToomas Soome
29630c75cb0SToomas Soome static int
comc_init(struct console * cp,int arg __attribute ((unused)))29730c75cb0SToomas Soome comc_init(struct console *cp, int arg __attribute((unused)))
29830c75cb0SToomas Soome {
29930c75cb0SToomas Soome
300fec53dd4SToomas Soome if (comc_setup(cp))
30130c75cb0SToomas Soome return (CMD_OK);
302fec53dd4SToomas Soome
303fec53dd4SToomas Soome cp->c_flags = 0;
30430c75cb0SToomas Soome return (CMD_ERROR);
30530c75cb0SToomas Soome }
30630c75cb0SToomas Soome
30730c75cb0SToomas Soome static void
comc_putchar(struct console * cp,int c)30830c75cb0SToomas Soome comc_putchar(struct console *cp, int c)
30930c75cb0SToomas Soome {
31030c75cb0SToomas Soome int wait;
31130c75cb0SToomas Soome EFI_STATUS status;
31230c75cb0SToomas Soome UINTN bufsz = 1;
31330c75cb0SToomas Soome char cb = c;
31430c75cb0SToomas Soome struct serial *sp = cp->c_private;
31530c75cb0SToomas Soome
31630c75cb0SToomas Soome if (sp->sio == NULL)
31730c75cb0SToomas Soome return;
31830c75cb0SToomas Soome
31930c75cb0SToomas Soome for (wait = COMC_TXWAIT; wait > 0; wait--) {
32030c75cb0SToomas Soome status = sp->sio->Write(sp->sio, &bufsz, &cb);
32130c75cb0SToomas Soome if (status != EFI_TIMEOUT)
32230c75cb0SToomas Soome break;
32330c75cb0SToomas Soome }
32430c75cb0SToomas Soome }
32530c75cb0SToomas Soome
32630c75cb0SToomas Soome static int
comc_getchar(struct console * cp)32730c75cb0SToomas Soome comc_getchar(struct console *cp)
32830c75cb0SToomas Soome {
32930c75cb0SToomas Soome EFI_STATUS status;
33030c75cb0SToomas Soome UINTN bufsz = 1;
33130c75cb0SToomas Soome char c;
33230c75cb0SToomas Soome struct serial *sp = cp->c_private;
33330c75cb0SToomas Soome
33430c75cb0SToomas Soome if (sp->sio == NULL || !comc_ischar(cp))
33530c75cb0SToomas Soome return (-1);
33630c75cb0SToomas Soome
33730c75cb0SToomas Soome status = sp->sio->Read(sp->sio, &bufsz, &c);
33830c75cb0SToomas Soome if (EFI_ERROR(status) || bufsz == 0)
33930c75cb0SToomas Soome return (-1);
34030c75cb0SToomas Soome
34130c75cb0SToomas Soome return (c);
34230c75cb0SToomas Soome }
34330c75cb0SToomas Soome
34430c75cb0SToomas Soome static int
comc_ischar(struct console * cp)34530c75cb0SToomas Soome comc_ischar(struct console *cp)
34630c75cb0SToomas Soome {
34730c75cb0SToomas Soome EFI_STATUS status;
34830c75cb0SToomas Soome uint32_t control;
34930c75cb0SToomas Soome struct serial *sp = cp->c_private;
35030c75cb0SToomas Soome
35130c75cb0SToomas Soome if (sp->sio == NULL)
35230c75cb0SToomas Soome return (0);
35330c75cb0SToomas Soome
35430c75cb0SToomas Soome status = sp->sio->GetControl(sp->sio, &control);
35530c75cb0SToomas Soome if (EFI_ERROR(status))
35630c75cb0SToomas Soome return (0);
35730c75cb0SToomas Soome
358d656c9b5SToomas Soome return (!(control & EFI_SERIAL_INPUT_BUFFER_EMPTY));
35930c75cb0SToomas Soome }
36030c75cb0SToomas Soome
3619890ff83SToomas Soome static int
comc_ioctl(struct console * cp __unused,int cmd __unused,void * data __unused)3629890ff83SToomas Soome comc_ioctl(struct console *cp __unused, int cmd __unused, void *data __unused)
3639890ff83SToomas Soome {
3649890ff83SToomas Soome return (ENOTTY);
3659890ff83SToomas Soome }
3669890ff83SToomas Soome
36780e47917SToomas Soome static void
comc_devinfo(struct console * cp)36880e47917SToomas Soome comc_devinfo(struct console *cp)
36980e47917SToomas Soome {
37080e47917SToomas Soome struct serial *port = cp->c_private;
37180e47917SToomas Soome EFI_HANDLE handle;
37280e47917SToomas Soome EFI_DEVICE_PATH *dp;
37380e47917SToomas Soome CHAR16 *text;
37480e47917SToomas Soome
37580e47917SToomas Soome handle = efi_serial_get_handle(port->ioaddr);
37680e47917SToomas Soome if (handle == NULL) {
37780e47917SToomas Soome printf("\tdevice is not present");
37880e47917SToomas Soome return;
37980e47917SToomas Soome }
38080e47917SToomas Soome
38180e47917SToomas Soome dp = efi_lookup_devpath(handle);
38280e47917SToomas Soome if (dp == NULL)
38380e47917SToomas Soome return;
38480e47917SToomas Soome
38580e47917SToomas Soome text = efi_devpath_name(dp);
38680e47917SToomas Soome if (text == NULL)
38780e47917SToomas Soome return;
38880e47917SToomas Soome
38980e47917SToomas Soome printf("\t%S", text);
39080e47917SToomas Soome efi_free_devpath_name(text);
39180e47917SToomas Soome }
39280e47917SToomas Soome
39330c75cb0SToomas Soome static char *
comc_asprint_mode(struct serial * sp)39430c75cb0SToomas Soome comc_asprint_mode(struct serial *sp)
39530c75cb0SToomas Soome {
396cbae6195SToomas Soome char par, *buf;
397cbae6195SToomas Soome char *stop;
39830c75cb0SToomas Soome
39930c75cb0SToomas Soome if (sp == NULL)
40030c75cb0SToomas Soome return (NULL);
40130c75cb0SToomas Soome
40230c75cb0SToomas Soome switch (sp->parity) {
403cbae6195SToomas Soome case NoParity:
404cbae6195SToomas Soome par = 'n';
40530c75cb0SToomas Soome break;
406cbae6195SToomas Soome case EvenParity:
407cbae6195SToomas Soome par = 'e';
40830c75cb0SToomas Soome break;
409cbae6195SToomas Soome case OddParity:
410cbae6195SToomas Soome par = 'o';
411cbae6195SToomas Soome break;
412cbae6195SToomas Soome case MarkParity:
413cbae6195SToomas Soome par = 'm';
414cbae6195SToomas Soome break;
415cbae6195SToomas Soome case SpaceParity:
416cbae6195SToomas Soome par = 's';
417cbae6195SToomas Soome break;
418cbae6195SToomas Soome default:
419cbae6195SToomas Soome par = 'n';
42030c75cb0SToomas Soome break;
42130c75cb0SToomas Soome }
422cbae6195SToomas Soome
42330c75cb0SToomas Soome switch (sp->stopbits) {
424cbae6195SToomas Soome case OneStopBit:
425cbae6195SToomas Soome stop = "1";
426cbae6195SToomas Soome break;
427cbae6195SToomas Soome case TwoStopBits:
428cbae6195SToomas Soome stop = "2";
42930c75cb0SToomas Soome break;
430cbae6195SToomas Soome case OneFiveStopBits:
431cbae6195SToomas Soome stop = "1.5";
432cbae6195SToomas Soome break;
433cbae6195SToomas Soome default:
434cbae6195SToomas Soome stop = "1";
43530c75cb0SToomas Soome break;
43630c75cb0SToomas Soome }
43730c75cb0SToomas Soome
438cbae6195SToomas Soome asprintf(&buf, "%ju,%d,%c,%s,-", sp->baudrate, sp->databits, par, stop);
43930c75cb0SToomas Soome return (buf);
44030c75cb0SToomas Soome }
44130c75cb0SToomas Soome
44230c75cb0SToomas Soome static int
comc_parse_mode(struct serial * sp,const char * value)44330c75cb0SToomas Soome comc_parse_mode(struct serial *sp, const char *value)
44430c75cb0SToomas Soome {
44530c75cb0SToomas Soome unsigned long n;
44630c75cb0SToomas Soome uint64_t baudrate;
44730c75cb0SToomas Soome uint8_t databits = 8;
44830c75cb0SToomas Soome int parity = NoParity;
44930c75cb0SToomas Soome int stopbits = OneStopBit;
45030c75cb0SToomas Soome char *ep;
45130c75cb0SToomas Soome
45230c75cb0SToomas Soome if (value == NULL || *value == '\0')
45330c75cb0SToomas Soome return (CMD_ERROR);
45430c75cb0SToomas Soome
45530c75cb0SToomas Soome errno = 0;
45630c75cb0SToomas Soome n = strtoul(value, &ep, 10);
45730c75cb0SToomas Soome if (errno != 0 || *ep != ',')
45830c75cb0SToomas Soome return (CMD_ERROR);
45930c75cb0SToomas Soome baudrate = n;
46030c75cb0SToomas Soome
46130c75cb0SToomas Soome ep++;
46230c75cb0SToomas Soome n = strtoul(ep, &ep, 10);
46330c75cb0SToomas Soome if (errno != 0 || *ep != ',')
46430c75cb0SToomas Soome return (CMD_ERROR);
46530c75cb0SToomas Soome
46630c75cb0SToomas Soome switch (n) {
467cbae6195SToomas Soome case 5: databits = 5;
468cbae6195SToomas Soome break;
469cbae6195SToomas Soome case 6: databits = 6;
470cbae6195SToomas Soome break;
47130c75cb0SToomas Soome case 7: databits = 7;
47230c75cb0SToomas Soome break;
47330c75cb0SToomas Soome case 8: databits = 8;
47430c75cb0SToomas Soome break;
47530c75cb0SToomas Soome default:
47630c75cb0SToomas Soome return (CMD_ERROR);
47730c75cb0SToomas Soome }
47830c75cb0SToomas Soome
47930c75cb0SToomas Soome ep++;
48030c75cb0SToomas Soome switch (*ep++) {
48130c75cb0SToomas Soome case 'n': parity = NoParity;
48230c75cb0SToomas Soome break;
48330c75cb0SToomas Soome case 'e': parity = EvenParity;
48430c75cb0SToomas Soome break;
48530c75cb0SToomas Soome case 'o': parity = OddParity;
48630c75cb0SToomas Soome break;
487cbae6195SToomas Soome case 'm': parity = MarkParity;
488cbae6195SToomas Soome break;
489cbae6195SToomas Soome case 's': parity = SpaceParity;
490cbae6195SToomas Soome break;
49130c75cb0SToomas Soome default:
49230c75cb0SToomas Soome return (CMD_ERROR);
49330c75cb0SToomas Soome }
49430c75cb0SToomas Soome
49530c75cb0SToomas Soome if (*ep == ',')
49630c75cb0SToomas Soome ep++;
49730c75cb0SToomas Soome else
49830c75cb0SToomas Soome return (CMD_ERROR);
49930c75cb0SToomas Soome
50030c75cb0SToomas Soome switch (*ep++) {
50130c75cb0SToomas Soome case '1': stopbits = OneStopBit;
502cbae6195SToomas Soome if (ep[0] == '.' && ep[1] == '5') {
503cbae6195SToomas Soome ep += 2;
504cbae6195SToomas Soome stopbits = OneFiveStopBits;
505cbae6195SToomas Soome }
50630c75cb0SToomas Soome break;
50730c75cb0SToomas Soome case '2': stopbits = TwoStopBits;
50830c75cb0SToomas Soome break;
50930c75cb0SToomas Soome default:
51030c75cb0SToomas Soome return (CMD_ERROR);
51130c75cb0SToomas Soome }
51230c75cb0SToomas Soome
51330c75cb0SToomas Soome /* handshake is ignored, but we check syntax anyhow */
51430c75cb0SToomas Soome if (*ep == ',')
51530c75cb0SToomas Soome ep++;
51630c75cb0SToomas Soome else
51730c75cb0SToomas Soome return (CMD_ERROR);
51830c75cb0SToomas Soome
51930c75cb0SToomas Soome switch (*ep++) {
52030c75cb0SToomas Soome case '-':
52130c75cb0SToomas Soome case 'h':
52230c75cb0SToomas Soome case 's':
52330c75cb0SToomas Soome break;
52430c75cb0SToomas Soome default:
52530c75cb0SToomas Soome return (CMD_ERROR);
52630c75cb0SToomas Soome }
52730c75cb0SToomas Soome
52830c75cb0SToomas Soome if (*ep != '\0')
52930c75cb0SToomas Soome return (CMD_ERROR);
53030c75cb0SToomas Soome
53130c75cb0SToomas Soome sp->baudrate = baudrate;
53230c75cb0SToomas Soome sp->databits = databits;
53330c75cb0SToomas Soome sp->parity = parity;
53430c75cb0SToomas Soome sp->stopbits = stopbits;
53530c75cb0SToomas Soome return (CMD_OK);
53630c75cb0SToomas Soome }
53730c75cb0SToomas Soome
53830c75cb0SToomas Soome static struct console *
get_console(char * name)53930c75cb0SToomas Soome get_console(char *name)
54030c75cb0SToomas Soome {
54130c75cb0SToomas Soome struct console *cp = NULL;
54230c75cb0SToomas Soome
54330c75cb0SToomas Soome switch (name[3]) {
54430c75cb0SToomas Soome case 'a': cp = &ttya;
54530c75cb0SToomas Soome break;
54630c75cb0SToomas Soome case 'b': cp = &ttyb;
54730c75cb0SToomas Soome break;
54830c75cb0SToomas Soome case 'c': cp = &ttyc;
54930c75cb0SToomas Soome break;
55030c75cb0SToomas Soome case 'd': cp = &ttyd;
55130c75cb0SToomas Soome break;
55230c75cb0SToomas Soome }
55330c75cb0SToomas Soome return (cp);
55430c75cb0SToomas Soome }
55530c75cb0SToomas Soome
55630c75cb0SToomas Soome static int
comc_mode_set(struct env_var * ev,int flags,const void * value)55730c75cb0SToomas Soome comc_mode_set(struct env_var *ev, int flags, const void *value)
55830c75cb0SToomas Soome {
55930c75cb0SToomas Soome struct console *cp;
56030c75cb0SToomas Soome
56130c75cb0SToomas Soome if (value == NULL)
56230c75cb0SToomas Soome return (CMD_ERROR);
56330c75cb0SToomas Soome
56430c75cb0SToomas Soome if ((cp = get_console(ev->ev_name)) == NULL)
56530c75cb0SToomas Soome return (CMD_ERROR);
56630c75cb0SToomas Soome
56730c75cb0SToomas Soome if (comc_parse_mode(cp->c_private, value) == CMD_ERROR)
56830c75cb0SToomas Soome return (CMD_ERROR);
56930c75cb0SToomas Soome
570fec53dd4SToomas Soome (void) comc_setup(cp);
571fec53dd4SToomas Soome
57230c75cb0SToomas Soome env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
57330c75cb0SToomas Soome
57430c75cb0SToomas Soome return (CMD_OK);
57530c75cb0SToomas Soome }
57630c75cb0SToomas Soome
57730c75cb0SToomas Soome static int
comc_cd_set(struct env_var * ev,int flags,const void * value)57830c75cb0SToomas Soome comc_cd_set(struct env_var *ev, int flags, const void *value)
57930c75cb0SToomas Soome {
58030c75cb0SToomas Soome struct console *cp;
58130c75cb0SToomas Soome struct serial *sp;
58230c75cb0SToomas Soome
58330c75cb0SToomas Soome if (value == NULL)
58430c75cb0SToomas Soome return (CMD_ERROR);
58530c75cb0SToomas Soome
58630c75cb0SToomas Soome if ((cp = get_console(ev->ev_name)) == NULL)
58730c75cb0SToomas Soome return (CMD_ERROR);
58830c75cb0SToomas Soome
58930c75cb0SToomas Soome sp = cp->c_private;
59030c75cb0SToomas Soome if (strcmp(value, "true") == 0)
59130c75cb0SToomas Soome sp->ignore_cd = 1;
59230c75cb0SToomas Soome else if (strcmp(value, "false") == 0)
59330c75cb0SToomas Soome sp->ignore_cd = 0;
59430c75cb0SToomas Soome else
59530c75cb0SToomas Soome return (CMD_ERROR);
59630c75cb0SToomas Soome
597fec53dd4SToomas Soome (void) comc_setup(cp);
598fec53dd4SToomas Soome
59930c75cb0SToomas Soome env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
60030c75cb0SToomas Soome
60130c75cb0SToomas Soome return (CMD_OK);
60230c75cb0SToomas Soome }
60330c75cb0SToomas Soome
60430c75cb0SToomas Soome static int
comc_rtsdtr_set(struct env_var * ev,int flags,const void * value)60530c75cb0SToomas Soome comc_rtsdtr_set(struct env_var *ev, int flags, const void *value)
60630c75cb0SToomas Soome {
60730c75cb0SToomas Soome struct console *cp;
60830c75cb0SToomas Soome struct serial *sp;
60930c75cb0SToomas Soome
61030c75cb0SToomas Soome if (value == NULL)
61130c75cb0SToomas Soome return (CMD_ERROR);
61230c75cb0SToomas Soome
61330c75cb0SToomas Soome if ((cp = get_console(ev->ev_name)) == NULL)
61430c75cb0SToomas Soome return (CMD_ERROR);
61530c75cb0SToomas Soome
61630c75cb0SToomas Soome sp = cp->c_private;
61730c75cb0SToomas Soome if (strcmp(value, "true") == 0)
61830c75cb0SToomas Soome sp->rtsdtr_off = 1;
61930c75cb0SToomas Soome else if (strcmp(value, "false") == 0)
62030c75cb0SToomas Soome sp->rtsdtr_off = 0;
62130c75cb0SToomas Soome else
62230c75cb0SToomas Soome return (CMD_ERROR);
62330c75cb0SToomas Soome
624fec53dd4SToomas Soome (void) comc_setup(cp);
625fec53dd4SToomas Soome
62630c75cb0SToomas Soome env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
62730c75cb0SToomas Soome
62830c75cb0SToomas Soome return (CMD_OK);
62930c75cb0SToomas Soome }
63030c75cb0SToomas Soome
631fec53dd4SToomas Soome /*
632fec53dd4SToomas Soome * In case of error, we also reset ACTIVE flags, so the console
633fec53dd4SToomas Soome * framefork will try alternate consoles.
634fec53dd4SToomas Soome */
635fec53dd4SToomas Soome static bool
comc_setup(struct console * cp)63630c75cb0SToomas Soome comc_setup(struct console *cp)
63730c75cb0SToomas Soome {
63830c75cb0SToomas Soome EFI_STATUS status;
63930c75cb0SToomas Soome UINT32 control;
64030c75cb0SToomas Soome struct serial *sp = cp->c_private;
64130c75cb0SToomas Soome
64230c75cb0SToomas Soome /* port is not usable */
643fec53dd4SToomas Soome if (sp->sio == NULL)
644fec53dd4SToomas Soome return (false);
64530c75cb0SToomas Soome
64630c75cb0SToomas Soome status = sp->sio->Reset(sp->sio);
647fec53dd4SToomas Soome if (EFI_ERROR(status))
648fec53dd4SToomas Soome return (false);
64930c75cb0SToomas Soome
65030c75cb0SToomas Soome status = sp->sio->SetAttributes(sp->sio, sp->baudrate, 0, 0, sp->parity,
65130c75cb0SToomas Soome sp->databits, sp->stopbits);
652fec53dd4SToomas Soome if (EFI_ERROR(status))
653fec53dd4SToomas Soome return (false);
65430c75cb0SToomas Soome
655ada70d03SToomas Soome status = sp->sio->GetControl(sp->sio, &control);
656ada70d03SToomas Soome if (EFI_ERROR(status))
657ada70d03SToomas Soome return (false);
65830c75cb0SToomas Soome if (sp->rtsdtr_off) {
65930c75cb0SToomas Soome control &= ~(EFI_SERIAL_REQUEST_TO_SEND |
66030c75cb0SToomas Soome EFI_SERIAL_DATA_TERMINAL_READY);
661ada70d03SToomas Soome } else {
662ada70d03SToomas Soome control |= EFI_SERIAL_REQUEST_TO_SEND;
66330c75cb0SToomas Soome }
664ada70d03SToomas Soome
665ada70d03SToomas Soome (void) sp->sio->SetControl(sp->sio, control);
666ada70d03SToomas Soome
667fec53dd4SToomas Soome /* Mark this port usable. */
668fec53dd4SToomas Soome cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
669fec53dd4SToomas Soome return (true);
67030c75cb0SToomas Soome }
671