term/serial: Add ability to specify MMIO ports via "serial" command
This adds the ability to explicitly add an MMIO based serial port
via the "serial" command. The syntax is:
serial --port=mmio,<hex_address>{.b,.w,.l,.q}
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
parent
f5e1d23a18
commit
c4e8016316
@ -4168,8 +4168,24 @@ Commands usable anywhere in the menu and in the command-line.
|
||||
@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
|
||||
@ -4185,6 +4201,12 @@ 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}).
|
||||
|
||||
Examples:
|
||||
@example
|
||||
serial --port=3f8 --speed=9600
|
||||
serial --port=mmio,fefb0000.l --speed=115200
|
||||
@end example
|
||||
|
||||
See also @ref{Serial terminal}.
|
||||
@end deffn
|
||||
|
||||
|
||||
@ -164,6 +164,70 @@ grub_serial_find (const char *name)
|
||||
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)
|
||||
@ -215,8 +279,11 @@ grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user