@deffn Command serial [@option{--unit=unit}] [@option{--port=port}] [@option{--speed=speed}] [@option{--word=word}] [@option{--parity=parity}] [@option{--stop=stop}]
Initialize a serial device. @var{unit} is a number in the range 0-3
specifying which serial port to use; default is 0, which corresponds to
-the port often called COM1. @var{port} is the I/O port where the UART
-is to be found; if specified it takes precedence over @var{unit}.
+the port often called COM1.
+
+@var{port} is the I/O port where the UART is to be found or, if prefixed
+with @samp{mmio,}, the MMIO address of the UART. If specified it takes
+precedence over @var{unit}.
+
+Additionally, an MMIO address can be suffixed with:
+@itemize @bullet
+@item
+@samp{.b} for bytes access (default)
+@item
+@samp{.w} for 16-bit word access
+@item
+@samp{.l} for 32-bit long word access or
+@item
+@samp{.q} for 64-bit long long word access
+@end itemize
+
@var{speed} is the transmission speed; default is 9600. @var{word} and
@var{stop} are the number of data bits and stop bits. Data bits must
be in the range 5-8 and stop bits must be 1 or 2. Default is 8 data
@command{terminal_input} or @command{terminal_output} command is used
(@pxref{terminal_input}, @pxref{terminal_output}).
+Examples:
+@example
+serial --port=3f8 --speed=9600
+serial --port=mmio,fefb0000.l --speed=115200
+@end example
+
See also @ref{Serial terminal}.
@end deffn
if (grub_strcmp (port->name, name) == 0)
break;
}
+ if (!port && grub_strncmp (name, "mmio,", sizeof ("mmio,") - 1) == 0
+ && grub_isxdigit (name [sizeof ("mmio,") - 1]))
+ {
+ const char *p1, *p = &name[sizeof ("mmio,") - 1];
+ grub_addr_t addr = grub_strtoul (p, &p1, 16);
+ unsigned int acc_size = 1;
+ unsigned int nlen = p1 - p;
+
+ /*
+ * If we reach here, we know there's a digit after "mmio,", so
+ * all we need to check is the validity of the character following
+ * the number, which should be a termination, or a dot followed by
+ * an access size.
+ */
+ if (p1[0] != '\0' && p1[0] != '.')
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("incorrect MMIO address syntax"));
+ return NULL;
+ }
+ if (p1[0] == '.')
+ switch(p1[1])
+ {
+ case 'w':
+ acc_size = 2;
+ break;
+ case 'l':
+ acc_size = 3;
+ break;
+ case 'q':
+ acc_size = 4;
+ break;
+ case 'b':
+ acc_size = 1;
+ break;
+ default:
+ /*
+ * Should we abort for an unknown size? Let's just default
+ * to 1 byte, it would increase the chance that the user who
+ * did a typo can actually see the console.
+ */
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("incorrect MMIO access size"));
+ }
+
+ /*
+ * Specifying the access size is optional an grub_serial_ns8250_add_mmio()
+ * will not add it to the name. So the original loop trying to match an
+ * existing port above might have missed this one. Let's do another
+ * search ignoring the access size part of the string. At this point
+ * nlen contains the length of the name up to the end of the address.
+ */
+ FOR_SERIAL_PORTS (port)
+ if (grub_strncmp (port->name, name, nlen) == 0) {
+ break;
+ }
+
+ name = grub_serial_ns8250_add_mmio (addr, acc_size, NULL);
+ if (name == NULL)
+ return NULL;
+
+ FOR_SERIAL_PORTS (port)
+ 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)
if (state[OPTION_PORT].set)
{
- grub_snprintf (pname, sizeof (pname), "port%lx",
- grub_strtoul (state[1].arg, 0, 0));
+ if (grub_strncmp (state[OPTION_PORT].arg, "mmio,", sizeof ("mmio,") - 1) == 0)
+ grub_snprintf (pname, sizeof (pname), "%s", state[1].arg);
+ else
+ grub_snprintf (pname, sizeof (pname), "port%lx",
+ grub_strtoul (state[1].arg, 0, 0));
name = pname;
}