Add a "comconsole_speed" loader variable that can be used to change

the serial console speed (i386 and amd64 only). If the previous
stage boot loader requested a serial console (RB_SERIAL or RB_MULTIPLE)
then the default speed is determined from the current serial port
speed. Otherwise it is set to 9600 or the value of BOOT_COMCONSOLE_SPEED
at compile time.

This makes it possible to set the serial port speed once in
/boot.config and the setting will propagate to boot2, loader and
the kernel serial console.
This commit is contained in:
iedowse 2005-08-18 01:39:43 +00:00
parent 1161399eef
commit 11293f3595
4 changed files with 136 additions and 11 deletions

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 27, 2005
.Dd August 18, 2005
.Dt LOADER 8
.Os
.Sh NAME
@ -392,6 +392,19 @@ by the kernel during the boot phase.
List of semicolon-separated search path for bootable kernels.
The default is
.Dq Li kernel .
.It Va comconsole_speed
Defines the speed of the serial console (i386 and amd64 only).
If the previous boot stage indicated that a serial console is in use
then this variable is initialized to the current speed of the console
serial port.
Otherwise it is set to 9600 unless this was overridden using the
.Va BOOT_COMCONSOLE_SPEED
variable when
.Nm
was compiled.
Changes to the
.Va comconsole_speed
variable take effect immediately.
.It Va console
Defines the current console or consoles.
Multiple consoles may be specified.

View File

@ -47,6 +47,7 @@ loader_color="NO" # Set this to YES to enable splash screen colors
# allowed to interrupt autoboot process and
# escape to the loader prompt
#beastie_disable="NO" # Turn the beastie boot menu on and off
#comconsole_speed="9600" # Set the current serial console speed
#console="vidconsole" # A comma separated list of console(s)
#currdev="disk1s1a" # Set the current device
module_path="/boot/modules" # Set the module search path

View File

@ -23,7 +23,7 @@
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.Dd November 7, 2004
.Dd August 18, 2005
.Dt LOADER.CONF 5
.Os
.Sh NAME
@ -164,6 +164,18 @@ a bitmap will be loaded to be displayed on screen while booting.
.Pq Dq Pa /boot/splash.bmp
Name of the bitmap to be loaded.
Any other name can be used.
.It Va comconsole_speed
.Po Dq 9600
or the value of the
.Va BOOT_COMCONSOLE_SPEED
variable when
.Xr loader 8
was compiled
.Pc .
Sets the speed of the serial console.
If the previous boot loader stage specified that a serial console
is in use then the default speed is determined from the current
serial port speed setting.
.It Va console
.Pq Dq vidconsole
.Dq comconsole

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#define COMC_FMT 0x3 /* 8N1 */
#define COMC_TXWAIT 0x40000 /* transmit timeout */
#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */
#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */
#ifndef COMPORT
#define COMPORT 0x3f8
@ -47,9 +48,15 @@ static void comc_probe(struct console *cp);
static int comc_init(int arg);
static void comc_putchar(int c);
static int comc_getchar(void);
static int comc_getspeed(void);
static int comc_ischar(void);
static int comc_parsespeed(const char *string);
static void comc_setup(int speed);
static int comc_speed_set(struct env_var *ev, int flags,
const void *value);
static int comc_started;
static int comc_curspeed;
struct console comconsole = {
"comconsole",
@ -65,8 +72,36 @@ struct console comconsole = {
static void
comc_probe(struct console *cp)
{
char speedbuf[16];
char *cons, *speedenv;
int speed;
/* XXX check the BIOS equipment list? */
cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
if (comc_curspeed == 0) {
comc_curspeed = COMSPEED;
/*
* Assume that the speed was set by an earlier boot loader if
* comconsole is already the preferred console.
*/
cons = getenv("console");
if ((cons != NULL && strcmp(cons, comconsole.c_name) == 0) ||
getenv("boot_multicons") != NULL) {
comc_curspeed = comc_getspeed();
}
speedenv = getenv("comconsole_speed");
if (speedenv != NULL) {
speed = comc_parsespeed(speedenv);
if (speed > 0)
comc_curspeed = speed;
}
sprintf(speedbuf, "%d", comc_curspeed);
unsetenv("comconsole_speed");
env_setenv("comconsole_speed", EV_VOLATILE, speedbuf, comc_speed_set,
env_nounset);
}
}
static int
@ -76,15 +111,7 @@ comc_init(int arg)
return 0;
comc_started = 1;
outb(COMPORT + com_cfcr, CFCR_DLAB | COMC_FMT);
outb(COMPORT + com_dlbl, COMC_BPS(COMSPEED) & 0xff);
outb(COMPORT + com_dlbh, COMC_BPS(COMSPEED) >> 8);
outb(COMPORT + com_cfcr, COMC_FMT);
outb(COMPORT + com_mcr, MCR_RTS | MCR_DTR);
do
inb(COMPORT + com_data);
while (inb(COMPORT + com_lsr) & LSR_RXRDY);
comc_setup(comc_curspeed);
return(0);
}
@ -112,3 +139,75 @@ comc_ischar(void)
{
return(inb(COMPORT + com_lsr) & LSR_RXRDY);
}
static int
comc_speed_set(struct env_var *ev, int flags, const void *value)
{
int speed;
if (value == NULL || (speed = comc_parsespeed(value)) <= 0) {
printf("Invalid speed\n");
return (CMD_ERROR);
}
if (comc_started && comc_curspeed != speed)
comc_setup(speed);
env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
return (CMD_OK);
}
static void
comc_setup(int speed)
{
comc_curspeed = speed;
outb(COMPORT + com_cfcr, CFCR_DLAB | COMC_FMT);
outb(COMPORT + com_dlbl, COMC_BPS(speed) & 0xff);
outb(COMPORT + com_dlbh, COMC_BPS(speed) >> 8);
outb(COMPORT + com_cfcr, COMC_FMT);
outb(COMPORT + com_mcr, MCR_RTS | MCR_DTR);
do
inb(COMPORT + com_data);
while (inb(COMPORT + com_lsr) & LSR_RXRDY);
}
static int
comc_parsespeed(const char *speedstr)
{
char *p;
int speed;
speed = strtol(speedstr, &p, 0);
if (p == speedstr || *p != '\0' || speed <= 0)
return (-1);
return (speed);
}
static int
comc_getspeed(void)
{
u_int divisor;
u_char dlbh;
u_char dlbl;
u_char cfcr;
cfcr = inb(COMPORT + com_cfcr);
outb(COMPORT + com_cfcr, CFCR_DLAB | cfcr);
dlbl = inb(COMPORT + com_dlbl);
dlbh = inb(COMPORT + com_dlbh);
outb(COMPORT + com_cfcr, cfcr);
divisor = dlbh << 8 | dlbl;
/* XXX there should be more sanity checking. */
if (divisor == 0)
return (COMSPEED);
return (COMC_DIV2BPS(divisor));
}