diff --git a/sys/boot/common/loader.8 b/sys/boot/common/loader.8 index 13331c1a416d..3e99eeaca98b 100644 --- a/sys/boot/common/loader.8 +++ b/sys/boot/common/loader.8 @@ -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. diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf index 8f97c1f5ac31..fcaf4e5ade4e 100644 --- a/sys/boot/forth/loader.conf +++ b/sys/boot/forth/loader.conf @@ -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 diff --git a/sys/boot/forth/loader.conf.5 b/sys/boot/forth/loader.conf.5 index 4ee8b98fa13e..9d113e515d08 100644 --- a/sys/boot/forth/loader.conf.5 +++ b/sys/boot/forth/loader.conf.5 @@ -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 diff --git a/sys/boot/i386/libi386/comconsole.c b/sys/boot/i386/libi386/comconsole.c index 1b08d9bdd7ac..fa2b1b5074d6 100644 --- a/sys/boot/i386/libi386/comconsole.c +++ b/sys/boot/i386/libi386/comconsole.c @@ -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)); +}