command accepts many other options, so please refer to @ref{serial},
for more details.
+Without argument or with @samp{--port=auto}, GRUB will attempt to use
+ACPI when available to auto-detect the default serial port and its
+configuration.
+
The commands @command{terminal_input} (@pxref{terminal_input}) and
@command{terminal_output} (@pxref{terminal_output}) choose which type of
terminal you want to use. In the case above, the terminal will be a
bits and one stop bit. @var{parity} is one of @samp{no}, @samp{odd},
@samp{even} and defaults to @samp{no}.
+If passed no @var{unit} nor @var{port}, or if @var{port} is set to
+@samp{auto} then GRUB will attempt to use ACPI to automatically detect
+the system default serial port and its configuration. If this information
+is not available, it will default to @var{unit} 0.
+
The serial port is not used as a communication channel unless the
@command{terminal_input} or @command{terminal_output} command is used
(@pxref{terminal_input}, @pxref{terminal_output}).
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined(GRUB_MACHINE_IEEE1275) && !defined(GRUB_MACHINE_QEMU)
+
+#include <grub/serial.h>
+#include <grub/ns8250.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/acpi.h>
+
+char *
+grub_ns8250_spcr_init (void)
+{
+ struct grub_acpi_spcr *spcr;
+ struct grub_serial_config config;
+
+ spcr = grub_acpi_find_table (GRUB_ACPI_SPCR_SIGNATURE);
+ if (spcr == NULL)
+ return NULL;
+ if (spcr->hdr.revision < 2)
+ return NULL;
+ if (spcr->intf_type != GRUB_ACPI_SPCR_INTF_TYPE_16550 &&
+ spcr->intf_type != GRUB_ACPI_SPCR_INTF_TYPE_16550X)
+ return NULL;
+ /* For now, we only support byte accesses. */
+ if (spcr->base_addr.access_size != GRUB_ACPI_GENADDR_SIZE_BYTE &&
+ spcr->base_addr.access_size != GRUB_ACPI_GENADDR_SIZE_LGCY)
+ return NULL;
+ config.word_len = 8;
+ config.parity = GRUB_SERIAL_PARITY_NONE;
+ config.stop_bits = GRUB_SERIAL_STOP_BITS_1;
+ config.base_clock = UART_DEFAULT_BASE_CLOCK;
+ if (spcr->flow_control & GRUB_ACPI_SPCR_FC_RTSCTS)
+ config.rtscts = 1;
+ else
+ config.rtscts = 0;
+ switch (spcr->baud_rate)
+ {
+ case GRUB_ACPI_SPCR_BAUD_9600:
+ config.speed = 9600;
+ break;
+ case GRUB_ACPI_SPCR_BAUD_19200:
+ config.speed = 19200;
+ break;
+ case GRUB_ACPI_SPCR_BAUD_57600:
+ config.speed = 57600;
+ break;
+ case GRUB_ACPI_SPCR_BAUD_115200:
+ config.speed = 115200;
+ break;
+ case GRUB_ACPI_SPCR_BAUD_CURRENT:
+ default:
+ /*
+ * We don't (yet) have a way to read the currently
+ * configured speed in HW, so let's use a sane default.
+ */
+ config.speed = 115200;
+ break;
+ };
+ switch (spcr->base_addr.space_id)
+ {
+ case GRUB_ACPI_GENADDR_MEM_SPACE:
+ return grub_serial_ns8250_add_mmio (spcr->base_addr.addr, &config);
+ case GRUB_ACPI_GENADDR_IO_SPACE:
+ return grub_serial_ns8250_add_port (spcr->base_addr.addr, &config);
+ default:
+ return NULL;
+ };
+}
+
+#endif
{
name = grub_serial_ns8250_add_port (grub_strtoul (&name[sizeof ("port") - 1],
0, 16), NULL);
- if (!name)
- return NULL;
+ if (name == NULL)
+ return NULL;
FOR_SERIAL_PORTS (port)
- if (grub_strcmp (port->name, name) == 0)
- break;
+ if (grub_strcmp (port->name, name) == 0)
+ break;
+ }
+
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_IEEE1275) && !defined(GRUB_MACHINE_QEMU)
+ if (!port && grub_strcmp (name, "auto") == 0)
+ {
+ /* Look for an SPCR if any. If not, default to com0. */
+ name = grub_ns8250_spcr_init ();
+ if (name == NULL)
+ name = "com0";
+
+ FOR_SERIAL_PORTS (port)
+ if (grub_strcmp (port->name, name) == 0)
+ break;
}
#endif
+#endif
#ifdef GRUB_MACHINE_IEEE1275
if (!port && grub_memcmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) == 0)
name = args[0];
if (!name)
- name = "com0";
+ name = "auto";
port = grub_serial_find (name);
if (!port)