122028508SToomas Soome /*
222028508SToomas Soome * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
322028508SToomas Soome *
422028508SToomas Soome * Redistribution and use in source and binary forms, with or without
522028508SToomas Soome * modification, are permitted provided that the following conditions
622028508SToomas Soome * are met:
722028508SToomas Soome * 1. Redistributions of source code must retain the above copyright
822028508SToomas Soome * notice, this list of conditions and the following disclaimer.
922028508SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
1022028508SToomas Soome * notice, this list of conditions and the following disclaimer in the
1122028508SToomas Soome * documentation and/or other materials provided with the distribution.
1222028508SToomas Soome *
1322028508SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1422028508SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1522028508SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1622028508SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1722028508SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1822028508SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1922028508SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2022028508SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2122028508SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2222028508SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2322028508SToomas Soome * SUCH DAMAGE.
2422028508SToomas Soome */
2522028508SToomas Soome
2622028508SToomas Soome /*
2722028508SToomas Soome * We do not use this implementation with x86 till we can fix two issues:
2822028508SToomas Soome * 1. Reliably identify the serial ports in correct order.
2922028508SToomas Soome * 2. Ensure we get properly working reads from serial io.
3022028508SToomas Soome */
3122028508SToomas Soome
3222028508SToomas Soome #include <sys/cdefs.h>
3322028508SToomas Soome
3422028508SToomas Soome #include <stand.h>
3522028508SToomas Soome #include <sys/errno.h>
3622028508SToomas Soome #include <bootstrap.h>
3722028508SToomas Soome #include <stdbool.h>
3822028508SToomas Soome
3922028508SToomas Soome #include <efi.h>
4022028508SToomas Soome #include <efilib.h>
41*f334afcfSToomas Soome #include <Protocol/SerialIo.h>
4222028508SToomas Soome
4322028508SToomas Soome #include "loader_efi.h"
4422028508SToomas 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;
4822028508SToomas Soome
4922028508SToomas Soome #define COMC_TXWAIT 0x40000 /* transmit timeout */
5022028508SToomas Soome
5122028508SToomas Soome #ifndef COMSPEED
5222028508SToomas Soome #define COMSPEED 9600
5322028508SToomas Soome #endif
5422028508SToomas Soome
5522028508SToomas Soome #define PNP0501 0x501 /* 16550A-compatible COM port */
5622028508SToomas Soome
5722028508SToomas Soome struct serial {
5822028508SToomas Soome uint64_t baudrate;
5922028508SToomas Soome uint8_t databits;
6022028508SToomas Soome EFI_PARITY_TYPE parity;
6122028508SToomas Soome EFI_STOP_BITS_TYPE stopbits;
6222028508SToomas Soome uint8_t ignore_cd; /* boolean */
6322028508SToomas Soome uint8_t rtsdtr_off; /* boolean */
6422028508SToomas Soome int ioaddr; /* index in handles array */
6522028508SToomas Soome SERIAL_IO_INTERFACE *sio;
6622028508SToomas Soome };
6722028508SToomas Soome
6822028508SToomas Soome static void comc_probe(struct console *);
6922028508SToomas Soome static int comc_init(struct console *, int);
7022028508SToomas Soome static void comc_putchar(struct console *, int);
7122028508SToomas Soome static int comc_getchar(struct console *);
7222028508SToomas Soome static int comc_ischar(struct console *);
7322028508SToomas Soome static int comc_ioctl(struct console *, int, void *);
7422028508SToomas Soome static void comc_devinfo(struct console *);
7522028508SToomas Soome static bool comc_setup(struct console *);
7622028508SToomas Soome static char *comc_asprint_mode(struct serial *);
7722028508SToomas Soome static int comc_parse_mode(struct serial *, const char *);
7822028508SToomas Soome static int comc_mode_set(struct env_var *, int, const void *);
7922028508SToomas Soome static int comc_cd_set(struct env_var *, int, const void *);
8022028508SToomas Soome static int comc_rtsdtr_set(struct env_var *, int, const void *);
8122028508SToomas Soome
8222028508SToomas Soome struct console ttya = {
8322028508SToomas Soome .c_name = "ttya",
8422028508SToomas Soome .c_desc = "serial port a",
8522028508SToomas Soome .c_flags = 0,
8622028508SToomas Soome .c_probe = comc_probe,
8722028508SToomas Soome .c_init = comc_init,
8822028508SToomas Soome .c_out = comc_putchar,
8922028508SToomas Soome .c_in = comc_getchar,
9022028508SToomas Soome .c_ready = comc_ischar,
9122028508SToomas Soome .c_ioctl = comc_ioctl,
9222028508SToomas Soome .c_devinfo = comc_devinfo,
9322028508SToomas Soome .c_private = NULL
9422028508SToomas Soome };
9522028508SToomas Soome
9622028508SToomas Soome struct console ttyb = {
9722028508SToomas Soome .c_name = "ttyb",
9822028508SToomas Soome .c_desc = "serial port b",
9922028508SToomas Soome .c_flags = 0,
10022028508SToomas Soome .c_probe = comc_probe,
10122028508SToomas Soome .c_init = comc_init,
10222028508SToomas Soome .c_out = comc_putchar,
10322028508SToomas Soome .c_in = comc_getchar,
10422028508SToomas Soome .c_ready = comc_ischar,
10522028508SToomas Soome .c_ioctl = comc_ioctl,
10622028508SToomas Soome .c_devinfo = comc_devinfo,
10722028508SToomas Soome .c_private = NULL
10822028508SToomas Soome };
10922028508SToomas Soome
11022028508SToomas Soome struct console ttyc = {
11122028508SToomas Soome .c_name = "ttyc",
11222028508SToomas Soome .c_desc = "serial port c",
11322028508SToomas Soome .c_flags = 0,
11422028508SToomas Soome .c_probe = comc_probe,
11522028508SToomas Soome .c_init = comc_init,
11622028508SToomas Soome .c_out = comc_putchar,
11722028508SToomas Soome .c_in = comc_getchar,
11822028508SToomas Soome .c_ready = comc_ischar,
11922028508SToomas Soome .c_ioctl = comc_ioctl,
12022028508SToomas Soome .c_devinfo = comc_devinfo,
12122028508SToomas Soome .c_private = NULL
12222028508SToomas Soome };
12322028508SToomas Soome
12422028508SToomas Soome struct console ttyd = {
12522028508SToomas Soome .c_name = "ttyd",
12622028508SToomas Soome .c_desc = "serial port d",
12722028508SToomas Soome .c_flags = 0,
12822028508SToomas Soome .c_probe = comc_probe,
12922028508SToomas Soome .c_init = comc_init,
13022028508SToomas Soome .c_out = comc_putchar,
13122028508SToomas Soome .c_in = comc_getchar,
13222028508SToomas Soome .c_ready = comc_ischar,
13322028508SToomas Soome .c_ioctl = comc_ioctl,
13422028508SToomas Soome .c_devinfo = comc_devinfo,
13522028508SToomas Soome .c_private = NULL
13622028508SToomas Soome };
13722028508SToomas Soome
13822028508SToomas Soome /*
13922028508SToomas Soome * Find serial device number from device path.
14022028508SToomas Soome * Return -1 if not found.
14122028508SToomas Soome */
14222028508SToomas Soome static int
efi_serial_get_index(EFI_DEVICE_PATH * devpath)14322028508SToomas Soome efi_serial_get_index(EFI_DEVICE_PATH *devpath)
14422028508SToomas Soome {
14522028508SToomas Soome ACPI_HID_DEVICE_PATH *acpi;
14622028508SToomas Soome
14722028508SToomas Soome while (!IsDevicePathEnd(devpath)) {
14822028508SToomas Soome if (DevicePathType(devpath) == ACPI_DEVICE_PATH &&
14922028508SToomas Soome DevicePathSubType(devpath) == ACPI_DP) {
15022028508SToomas Soome
15122028508SToomas Soome acpi = (ACPI_HID_DEVICE_PATH *)devpath;
15222028508SToomas Soome if (acpi->HID == EISA_PNP_ID(PNP0501)) {
15322028508SToomas Soome return (acpi->UID);
15422028508SToomas Soome }
15522028508SToomas Soome }
15622028508SToomas Soome
15722028508SToomas Soome devpath = NextDevicePathNode(devpath);
15822028508SToomas Soome }
15922028508SToomas Soome return (-1);
16022028508SToomas Soome }
16122028508SToomas Soome
16222028508SToomas Soome /*
16322028508SToomas Soome * The order of handles from LocateHandle() is not known, we need to
16422028508SToomas Soome * iterate handles, pick device path for handle, and check the device
16522028508SToomas Soome * number.
16622028508SToomas Soome */
16722028508SToomas Soome static EFI_HANDLE
efi_serial_get_handle(int port)16822028508SToomas Soome efi_serial_get_handle(int port)
16922028508SToomas Soome {
17022028508SToomas Soome EFI_STATUS status;
17122028508SToomas Soome EFI_HANDLE *handles, handle;
17222028508SToomas Soome EFI_DEVICE_PATH *devpath;
17369764de3SToomas Soome uint_t index, nhandles;
17422028508SToomas Soome
17522028508SToomas Soome if (port == -1)
17622028508SToomas Soome return (NULL);
17722028508SToomas Soome
178*f334afcfSToomas Soome status = efi_get_protocol_handles(&gEfiSerialIoProtocolGuid,
179*f334afcfSToomas Soome &nhandles, &handles);
18022028508SToomas Soome if (EFI_ERROR(status))
18122028508SToomas Soome return (NULL);
18222028508SToomas Soome
18322028508SToomas Soome handle = NULL;
18422028508SToomas Soome for (index = 0; index < nhandles; index++) {
18522028508SToomas Soome devpath = efi_lookup_devpath(handles[index]);
18622028508SToomas Soome if (port == efi_serial_get_index(devpath)) {
18722028508SToomas Soome handle = (handles[index]);
18822028508SToomas Soome break;
18922028508SToomas Soome }
19022028508SToomas Soome }
19122028508SToomas Soome
19222028508SToomas Soome /*
19322028508SToomas Soome * In case we did fail to identify the device by path, use port as
19422028508SToomas Soome * array index. Note, we did check port == -1 above.
19522028508SToomas Soome */
19622028508SToomas Soome if (port < nhandles && handle == NULL)
19722028508SToomas Soome handle = handles[port];
19822028508SToomas Soome
19922028508SToomas Soome free(handles);
20022028508SToomas Soome return (handle);
20122028508SToomas Soome }
20222028508SToomas Soome
20322028508SToomas Soome static void
comc_probe(struct console * cp)20422028508SToomas Soome comc_probe(struct console *cp)
20522028508SToomas Soome {
20622028508SToomas Soome EFI_STATUS status;
20722028508SToomas Soome EFI_HANDLE handle;
20822028508SToomas Soome struct serial *port;
20922028508SToomas Soome char name[20];
21022028508SToomas Soome char value[20];
21122028508SToomas Soome char *env;
21222028508SToomas Soome
21322028508SToomas Soome /* are we already set up? */
21422028508SToomas Soome if (cp->c_private != NULL)
21522028508SToomas Soome return;
21622028508SToomas Soome
21722028508SToomas Soome cp->c_private = malloc(sizeof (struct serial));
21822028508SToomas Soome port = cp->c_private;
21922028508SToomas Soome port->baudrate = COMSPEED;
22022028508SToomas Soome
22122028508SToomas Soome port->ioaddr = -1; /* invalid port */
22222028508SToomas Soome if (strcmp(cp->c_name, "ttya") == 0)
22322028508SToomas Soome port->ioaddr = 0;
22422028508SToomas Soome else if (strcmp(cp->c_name, "ttyb") == 0)
22522028508SToomas Soome port->ioaddr = 1;
22622028508SToomas Soome else if (strcmp(cp->c_name, "ttyc") == 0)
22722028508SToomas Soome port->ioaddr = 2;
22822028508SToomas Soome else if (strcmp(cp->c_name, "ttyd") == 0)
22922028508SToomas Soome port->ioaddr = 3;
23022028508SToomas Soome
23122028508SToomas Soome port->databits = 8; /* 8,n,1 */
23222028508SToomas Soome port->parity = NoParity; /* 8,n,1 */
23322028508SToomas Soome port->stopbits = OneStopBit; /* 8,n,1 */
23422028508SToomas Soome port->ignore_cd = 1; /* ignore cd */
23522028508SToomas Soome port->rtsdtr_off = 0; /* rts-dtr is on */
23622028508SToomas Soome port->sio = NULL;
23722028508SToomas Soome
23822028508SToomas Soome handle = efi_serial_get_handle(port->ioaddr);
23922028508SToomas Soome
24022028508SToomas Soome if (handle != NULL) {
241*f334afcfSToomas Soome status = BS->OpenProtocol(handle, &gEfiSerialIoProtocolGuid,
24222028508SToomas Soome (void**)&port->sio, IH, NULL,
24322028508SToomas Soome EFI_OPEN_PROTOCOL_GET_PROTOCOL);
24422028508SToomas Soome
24522028508SToomas Soome if (EFI_ERROR(status))
24622028508SToomas Soome port->sio = NULL;
24722028508SToomas Soome }
24822028508SToomas Soome
24922028508SToomas Soome snprintf(name, sizeof (name), "%s-mode", cp->c_name);
25022028508SToomas Soome env = getenv(name);
25122028508SToomas Soome
25222028508SToomas Soome if (env != NULL)
25322028508SToomas Soome (void) comc_parse_mode(port, env);
25422028508SToomas Soome
25522028508SToomas Soome env = comc_asprint_mode(port);
25622028508SToomas Soome
25722028508SToomas Soome if (env != NULL) {
25822028508SToomas Soome unsetenv(name);
25922028508SToomas Soome env_setenv(name, EV_VOLATILE, env, comc_mode_set, env_nounset);
26022028508SToomas Soome free(env);
26122028508SToomas Soome }
26222028508SToomas Soome
26322028508SToomas Soome snprintf(name, sizeof (name), "%s-ignore-cd", cp->c_name);
26422028508SToomas Soome env = getenv(name);
26522028508SToomas Soome if (env != NULL) {
26622028508SToomas Soome if (strcmp(env, "true") == 0)
26722028508SToomas Soome port->ignore_cd = 1;
26822028508SToomas Soome else if (strcmp(env, "false") == 0)
26922028508SToomas Soome port->ignore_cd = 0;
27022028508SToomas Soome }
27122028508SToomas Soome
27222028508SToomas Soome snprintf(value, sizeof (value), "%s",
27322028508SToomas Soome port->ignore_cd? "true" : "false");
27422028508SToomas Soome unsetenv(name);
27522028508SToomas Soome env_setenv(name, EV_VOLATILE, value, comc_cd_set, env_nounset);
27622028508SToomas Soome
27722028508SToomas Soome snprintf(name, sizeof (name), "%s-rts-dtr-off", cp->c_name);
27822028508SToomas Soome env = getenv(name);
27922028508SToomas Soome if (env != NULL) {
28022028508SToomas Soome if (strcmp(env, "true") == 0)
28122028508SToomas Soome port->rtsdtr_off = 1;
28222028508SToomas Soome else if (strcmp(env, "false") == 0)
28322028508SToomas Soome port->rtsdtr_off = 0;
28422028508SToomas Soome }
28522028508SToomas Soome
28622028508SToomas Soome snprintf(value, sizeof (value), "%s",
28722028508SToomas Soome port->rtsdtr_off? "true" : "false");
28822028508SToomas Soome unsetenv(name);
28922028508SToomas Soome env_setenv(name, EV_VOLATILE, value, comc_rtsdtr_set, env_nounset);
29022028508SToomas Soome
29122028508SToomas Soome cp->c_flags = 0;
29222028508SToomas Soome if (comc_setup(cp))
29322028508SToomas Soome cp->c_flags = C_PRESENTIN | C_PRESENTOUT;
29422028508SToomas Soome }
29522028508SToomas Soome
29622028508SToomas Soome static int
comc_init(struct console * cp,int arg __attribute ((unused)))29722028508SToomas Soome comc_init(struct console *cp, int arg __attribute((unused)))
29822028508SToomas Soome {
29922028508SToomas Soome
30022028508SToomas Soome if (comc_setup(cp))
30122028508SToomas Soome return (CMD_OK);
30222028508SToomas Soome
30322028508SToomas Soome cp->c_flags = 0;
30422028508SToomas Soome return (CMD_ERROR);
30522028508SToomas Soome }
30622028508SToomas Soome
30722028508SToomas Soome static void
comc_putchar(struct console * cp,int c)30822028508SToomas Soome comc_putchar(struct console *cp, int c)
30922028508SToomas Soome {
31022028508SToomas Soome int wait;
31122028508SToomas Soome EFI_STATUS status;
31222028508SToomas Soome UINTN bufsz = 1;
31322028508SToomas Soome char cb = c;
31422028508SToomas Soome struct serial *sp = cp->c_private;
31522028508SToomas Soome
31622028508SToomas Soome if (sp->sio == NULL)
31722028508SToomas Soome return;
31822028508SToomas Soome
31922028508SToomas Soome for (wait = COMC_TXWAIT; wait > 0; wait--) {
32022028508SToomas Soome status = sp->sio->Write(sp->sio, &bufsz, &cb);
32122028508SToomas Soome if (status != EFI_TIMEOUT)
32222028508SToomas Soome break;
32322028508SToomas Soome }
32422028508SToomas Soome }
32522028508SToomas Soome
32622028508SToomas Soome static int
comc_getchar(struct console * cp)32722028508SToomas Soome comc_getchar(struct console *cp)
32822028508SToomas Soome {
32922028508SToomas Soome EFI_STATUS status;
33022028508SToomas Soome UINTN bufsz = 1;
33122028508SToomas Soome char c;
33222028508SToomas Soome struct serial *sp = cp->c_private;
33322028508SToomas Soome
33422028508SToomas Soome if (sp->sio == NULL || !comc_ischar(cp))
33522028508SToomas Soome return (-1);
33622028508SToomas Soome
33722028508SToomas Soome status = sp->sio->Read(sp->sio, &bufsz, &c);
33822028508SToomas Soome if (EFI_ERROR(status) || bufsz == 0)
33922028508SToomas Soome return (-1);
34022028508SToomas Soome
34122028508SToomas Soome return (c);
34222028508SToomas Soome }
34322028508SToomas Soome
34422028508SToomas Soome static int
comc_ischar(struct console * cp)34522028508SToomas Soome comc_ischar(struct console *cp)
34622028508SToomas Soome {
34722028508SToomas Soome EFI_STATUS status;
34822028508SToomas Soome uint32_t control;
34922028508SToomas Soome struct serial *sp = cp->c_private;
35022028508SToomas Soome
35122028508SToomas Soome if (sp->sio == NULL)
35222028508SToomas Soome return (0);
35322028508SToomas Soome
35422028508SToomas Soome status = sp->sio->GetControl(sp->sio, &control);
35522028508SToomas Soome if (EFI_ERROR(status))
35622028508SToomas Soome return (0);
35722028508SToomas Soome
35822028508SToomas Soome return (!(control & EFI_SERIAL_INPUT_BUFFER_EMPTY));
35922028508SToomas Soome }
36022028508SToomas Soome
36122028508SToomas Soome static int
comc_ioctl(struct console * cp __unused,int cmd __unused,void * data __unused)36222028508SToomas Soome comc_ioctl(struct console *cp __unused, int cmd __unused, void *data __unused)
36322028508SToomas Soome {
36422028508SToomas Soome return (ENOTTY);
36522028508SToomas Soome }
36622028508SToomas Soome
36722028508SToomas Soome static void
comc_devinfo(struct console * cp)36822028508SToomas Soome comc_devinfo(struct console *cp)
36922028508SToomas Soome {
37022028508SToomas Soome struct serial *port = cp->c_private;
37122028508SToomas Soome EFI_HANDLE handle;
37222028508SToomas Soome EFI_DEVICE_PATH *dp;
37322028508SToomas Soome CHAR16 *text;
37422028508SToomas Soome
37522028508SToomas Soome handle = efi_serial_get_handle(port->ioaddr);
37622028508SToomas Soome if (handle == NULL) {
37722028508SToomas Soome printf("\tdevice is not present");
37822028508SToomas Soome return;
37922028508SToomas Soome }
38022028508SToomas Soome
38122028508SToomas Soome dp = efi_lookup_devpath(handle);
38222028508SToomas Soome if (dp == NULL)
38322028508SToomas Soome return;
38422028508SToomas Soome
38522028508SToomas Soome text = efi_devpath_name(dp);
38622028508SToomas Soome if (text == NULL)
38722028508SToomas Soome return;
38822028508SToomas Soome
38922028508SToomas Soome printf("\t%S", text);
39022028508SToomas Soome efi_free_devpath_name(text);
39122028508SToomas Soome }
39222028508SToomas Soome
39322028508SToomas Soome static char *
comc_asprint_mode(struct serial * sp)39422028508SToomas Soome comc_asprint_mode(struct serial *sp)
39522028508SToomas Soome {
39622028508SToomas Soome char par, *buf;
39722028508SToomas Soome char *stop;
39822028508SToomas Soome
39922028508SToomas Soome if (sp == NULL)
40022028508SToomas Soome return (NULL);
40122028508SToomas Soome
40222028508SToomas Soome switch (sp->parity) {
40322028508SToomas Soome case NoParity:
40422028508SToomas Soome par = 'n';
40522028508SToomas Soome break;
40622028508SToomas Soome case EvenParity:
40722028508SToomas Soome par = 'e';
40822028508SToomas Soome break;
40922028508SToomas Soome case OddParity:
41022028508SToomas Soome par = 'o';
41122028508SToomas Soome break;
41222028508SToomas Soome case MarkParity:
41322028508SToomas Soome par = 'm';
41422028508SToomas Soome break;
41522028508SToomas Soome case SpaceParity:
41622028508SToomas Soome par = 's';
41722028508SToomas Soome break;
41822028508SToomas Soome default:
41922028508SToomas Soome par = 'n';
42022028508SToomas Soome break;
42122028508SToomas Soome }
42222028508SToomas Soome
42322028508SToomas Soome switch (sp->stopbits) {
42422028508SToomas Soome case OneStopBit:
42522028508SToomas Soome stop = "1";
42622028508SToomas Soome break;
42722028508SToomas Soome case TwoStopBits:
42822028508SToomas Soome stop = "2";
42922028508SToomas Soome break;
43022028508SToomas Soome case OneFiveStopBits:
43122028508SToomas Soome stop = "1.5";
43222028508SToomas Soome break;
43322028508SToomas Soome default:
43422028508SToomas Soome stop = "1";
43522028508SToomas Soome break;
43622028508SToomas Soome }
43722028508SToomas Soome
43822028508SToomas Soome asprintf(&buf, "%ju,%d,%c,%s,-", sp->baudrate, sp->databits, par, stop);
43922028508SToomas Soome return (buf);
44022028508SToomas Soome }
44122028508SToomas Soome
44222028508SToomas Soome static int
comc_parse_mode(struct serial * sp,const char * value)44322028508SToomas Soome comc_parse_mode(struct serial *sp, const char *value)
44422028508SToomas Soome {
44522028508SToomas Soome unsigned long n;
44622028508SToomas Soome uint64_t baudrate;
44722028508SToomas Soome uint8_t databits = 8;
44822028508SToomas Soome int parity = NoParity;
44922028508SToomas Soome int stopbits = OneStopBit;
45022028508SToomas Soome char *ep;
45122028508SToomas Soome
45222028508SToomas Soome if (value == NULL || *value == '\0')
45322028508SToomas Soome return (CMD_ERROR);
45422028508SToomas Soome
45522028508SToomas Soome errno = 0;
45622028508SToomas Soome n = strtoul(value, &ep, 10);
45722028508SToomas Soome if (errno != 0 || *ep != ',')
45822028508SToomas Soome return (CMD_ERROR);
45922028508SToomas Soome baudrate = n;
46022028508SToomas Soome
46122028508SToomas Soome ep++;
46222028508SToomas Soome n = strtoul(ep, &ep, 10);
46322028508SToomas Soome if (errno != 0 || *ep != ',')
46422028508SToomas Soome return (CMD_ERROR);
46522028508SToomas Soome
46622028508SToomas Soome switch (n) {
46722028508SToomas Soome case 5: databits = 5;
46822028508SToomas Soome break;
46922028508SToomas Soome case 6: databits = 6;
47022028508SToomas Soome break;
47122028508SToomas Soome case 7: databits = 7;
47222028508SToomas Soome break;
47322028508SToomas Soome case 8: databits = 8;
47422028508SToomas Soome break;
47522028508SToomas Soome default:
47622028508SToomas Soome return (CMD_ERROR);
47722028508SToomas Soome }
47822028508SToomas Soome
47922028508SToomas Soome ep++;
48022028508SToomas Soome switch (*ep++) {
48122028508SToomas Soome case 'n': parity = NoParity;
48222028508SToomas Soome break;
48322028508SToomas Soome case 'e': parity = EvenParity;
48422028508SToomas Soome break;
48522028508SToomas Soome case 'o': parity = OddParity;
48622028508SToomas Soome break;
48722028508SToomas Soome case 'm': parity = MarkParity;
48822028508SToomas Soome break;
48922028508SToomas Soome case 's': parity = SpaceParity;
49022028508SToomas Soome break;
49122028508SToomas Soome default:
49222028508SToomas Soome return (CMD_ERROR);
49322028508SToomas Soome }
49422028508SToomas Soome
49522028508SToomas Soome if (*ep == ',')
49622028508SToomas Soome ep++;
49722028508SToomas Soome else
49822028508SToomas Soome return (CMD_ERROR);
49922028508SToomas Soome
50022028508SToomas Soome switch (*ep++) {
50122028508SToomas Soome case '1': stopbits = OneStopBit;
50222028508SToomas Soome if (ep[0] == '.' && ep[1] == '5') {
50322028508SToomas Soome ep += 2;
50422028508SToomas Soome stopbits = OneFiveStopBits;
50522028508SToomas Soome }
50622028508SToomas Soome break;
50722028508SToomas Soome case '2': stopbits = TwoStopBits;
50822028508SToomas Soome break;
50922028508SToomas Soome default:
51022028508SToomas Soome return (CMD_ERROR);
51122028508SToomas Soome }
51222028508SToomas Soome
51322028508SToomas Soome /* handshake is ignored, but we check syntax anyhow */
51422028508SToomas Soome if (*ep == ',')
51522028508SToomas Soome ep++;
51622028508SToomas Soome else
51722028508SToomas Soome return (CMD_ERROR);
51822028508SToomas Soome
51922028508SToomas Soome switch (*ep++) {
52022028508SToomas Soome case '-':
52122028508SToomas Soome case 'h':
52222028508SToomas Soome case 's':
52322028508SToomas Soome break;
52422028508SToomas Soome default:
52522028508SToomas Soome return (CMD_ERROR);
52622028508SToomas Soome }
52722028508SToomas Soome
52822028508SToomas Soome if (*ep != '\0')
52922028508SToomas Soome return (CMD_ERROR);
53022028508SToomas Soome
53122028508SToomas Soome sp->baudrate = baudrate;
53222028508SToomas Soome sp->databits = databits;
53322028508SToomas Soome sp->parity = parity;
53422028508SToomas Soome sp->stopbits = stopbits;
53522028508SToomas Soome return (CMD_OK);
53622028508SToomas Soome }
53722028508SToomas Soome
53822028508SToomas Soome static struct console *
get_console(char * name)53922028508SToomas Soome get_console(char *name)
54022028508SToomas Soome {
54122028508SToomas Soome struct console *cp = NULL;
54222028508SToomas Soome
54322028508SToomas Soome switch (name[3]) {
54422028508SToomas Soome case 'a': cp = &ttya;
54522028508SToomas Soome break;
54622028508SToomas Soome case 'b': cp = &ttyb;
54722028508SToomas Soome break;
54822028508SToomas Soome case 'c': cp = &ttyc;
54922028508SToomas Soome break;
55022028508SToomas Soome case 'd': cp = &ttyd;
55122028508SToomas Soome break;
55222028508SToomas Soome }
55322028508SToomas Soome return (cp);
55422028508SToomas Soome }
55522028508SToomas Soome
55622028508SToomas Soome static int
comc_mode_set(struct env_var * ev,int flags,const void * value)55722028508SToomas Soome comc_mode_set(struct env_var *ev, int flags, const void *value)
55822028508SToomas Soome {
55922028508SToomas Soome struct console *cp;
56022028508SToomas Soome
56122028508SToomas Soome if (value == NULL)
56222028508SToomas Soome return (CMD_ERROR);
56322028508SToomas Soome
56422028508SToomas Soome if ((cp = get_console(ev->ev_name)) == NULL)
56522028508SToomas Soome return (CMD_ERROR);
56622028508SToomas Soome
56722028508SToomas Soome if (comc_parse_mode(cp->c_private, value) == CMD_ERROR)
56822028508SToomas Soome return (CMD_ERROR);
56922028508SToomas Soome
57022028508SToomas Soome (void) comc_setup(cp);
57122028508SToomas Soome
57222028508SToomas Soome env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
57322028508SToomas Soome
57422028508SToomas Soome return (CMD_OK);
57522028508SToomas Soome }
57622028508SToomas Soome
57722028508SToomas Soome static int
comc_cd_set(struct env_var * ev,int flags,const void * value)57822028508SToomas Soome comc_cd_set(struct env_var *ev, int flags, const void *value)
57922028508SToomas Soome {
58022028508SToomas Soome struct console *cp;
58122028508SToomas Soome struct serial *sp;
58222028508SToomas Soome
58322028508SToomas Soome if (value == NULL)
58422028508SToomas Soome return (CMD_ERROR);
58522028508SToomas Soome
58622028508SToomas Soome if ((cp = get_console(ev->ev_name)) == NULL)
58722028508SToomas Soome return (CMD_ERROR);
58822028508SToomas Soome
58922028508SToomas Soome sp = cp->c_private;
59022028508SToomas Soome if (strcmp(value, "true") == 0)
59122028508SToomas Soome sp->ignore_cd = 1;
59222028508SToomas Soome else if (strcmp(value, "false") == 0)
59322028508SToomas Soome sp->ignore_cd = 0;
59422028508SToomas Soome else
59522028508SToomas Soome return (CMD_ERROR);
59622028508SToomas Soome
59722028508SToomas Soome (void) comc_setup(cp);
59822028508SToomas Soome
59922028508SToomas Soome env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
60022028508SToomas Soome
60122028508SToomas Soome return (CMD_OK);
60222028508SToomas Soome }
60322028508SToomas Soome
60422028508SToomas Soome static int
comc_rtsdtr_set(struct env_var * ev,int flags,const void * value)60522028508SToomas Soome comc_rtsdtr_set(struct env_var *ev, int flags, const void *value)
60622028508SToomas Soome {
60722028508SToomas Soome struct console *cp;
60822028508SToomas Soome struct serial *sp;
60922028508SToomas Soome
61022028508SToomas Soome if (value == NULL)
61122028508SToomas Soome return (CMD_ERROR);
61222028508SToomas Soome
61322028508SToomas Soome if ((cp = get_console(ev->ev_name)) == NULL)
61422028508SToomas Soome return (CMD_ERROR);
61522028508SToomas Soome
61622028508SToomas Soome sp = cp->c_private;
61722028508SToomas Soome if (strcmp(value, "true") == 0)
61822028508SToomas Soome sp->rtsdtr_off = 1;
61922028508SToomas Soome else if (strcmp(value, "false") == 0)
62022028508SToomas Soome sp->rtsdtr_off = 0;
62122028508SToomas Soome else
62222028508SToomas Soome return (CMD_ERROR);
62322028508SToomas Soome
62422028508SToomas Soome (void) comc_setup(cp);
62522028508SToomas Soome
62622028508SToomas Soome env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
62722028508SToomas Soome
62822028508SToomas Soome return (CMD_OK);
62922028508SToomas Soome }
63022028508SToomas Soome
63122028508SToomas Soome /*
63222028508SToomas Soome * In case of error, we also reset ACTIVE flags, so the console
63322028508SToomas Soome * framefork will try alternate consoles.
63422028508SToomas Soome */
63522028508SToomas Soome static bool
comc_setup(struct console * cp)63622028508SToomas Soome comc_setup(struct console *cp)
63722028508SToomas Soome {
63822028508SToomas Soome EFI_STATUS status;
63922028508SToomas Soome UINT32 control;
64022028508SToomas Soome struct serial *sp = cp->c_private;
64122028508SToomas Soome
64222028508SToomas Soome /* port is not usable */
64322028508SToomas Soome if (sp->sio == NULL)
64422028508SToomas Soome return (false);
64522028508SToomas Soome
64622028508SToomas Soome status = sp->sio->Reset(sp->sio);
64722028508SToomas Soome if (EFI_ERROR(status))
64822028508SToomas Soome return (false);
64922028508SToomas Soome
65022028508SToomas Soome status = sp->sio->SetAttributes(sp->sio, sp->baudrate, 0, 0, sp->parity,
65122028508SToomas Soome sp->databits, sp->stopbits);
65222028508SToomas Soome if (EFI_ERROR(status))
65322028508SToomas Soome return (false);
65422028508SToomas Soome
65522028508SToomas Soome status = sp->sio->GetControl(sp->sio, &control);
65622028508SToomas Soome if (EFI_ERROR(status))
65722028508SToomas Soome return (false);
65822028508SToomas Soome if (sp->rtsdtr_off) {
65922028508SToomas Soome control &= ~(EFI_SERIAL_REQUEST_TO_SEND |
66022028508SToomas Soome EFI_SERIAL_DATA_TERMINAL_READY);
66122028508SToomas Soome } else {
66222028508SToomas Soome control |= EFI_SERIAL_REQUEST_TO_SEND;
66322028508SToomas Soome }
66422028508SToomas Soome
66522028508SToomas Soome (void) sp->sio->SetControl(sp->sio, control);
66622028508SToomas Soome
66722028508SToomas Soome /* Mark this port usable. */
66822028508SToomas Soome cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
66922028508SToomas Soome return (true);
67022028508SToomas Soome }
671