comconsole.c revision 149213
1119482Sobrien/*- 238465Smsmith * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) 338465Smsmith * 438465Smsmith * Redistribution and use in source and binary forms, with or without 538465Smsmith * modification, are permitted provided that the following conditions 638465Smsmith * are met: 738465Smsmith * 1. Redistributions of source code must retain the above copyright 838465Smsmith * notice, this list of conditions and the following disclaimer. 938465Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1038465Smsmith * notice, this list of conditions and the following disclaimer in the 1138465Smsmith * documentation and/or other materials provided with the distribution. 1238465Smsmith * 1338465Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1438465Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1538465Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1638465Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1738465Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1838465Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1938465Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2038465Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2138465Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2238465Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2338465Smsmith * SUCH DAMAGE. 2438465Smsmith */ 2538465Smsmith 26119482Sobrien#include <sys/cdefs.h> 27119482Sobrien__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/comconsole.c 149213 2005-08-18 01:39:43Z iedowse $"); 28119482Sobrien 2938465Smsmith#include <stand.h> 3039441Smsmith#include <bootstrap.h> 3141285Srnordier#include <machine/cpufunc.h> 32120118Sbde#include <dev/ic/ns16550.h> 3339441Smsmith#include "libi386.h" 3438465Smsmith 3541285Srnordier#define COMC_FMT 0x3 /* 8N1 */ 3641285Srnordier#define COMC_TXWAIT 0x40000 /* transmit timeout */ 3741285Srnordier#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */ 38149213Siedowse#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */ 3941285Srnordier 4042480Srnordier#ifndef COMPORT 4141285Srnordier#define COMPORT 0x3f8 4242480Srnordier#endif 4342480Srnordier#ifndef COMSPEED 4441285Srnordier#define COMSPEED 9600 4542480Srnordier#endif 4641285Srnordier 4738465Smsmithstatic void comc_probe(struct console *cp); 4838465Smsmithstatic int comc_init(int arg); 4939441Smsmithstatic void comc_putchar(int c); 5039441Smsmithstatic int comc_getchar(void); 51149213Siedowsestatic int comc_getspeed(void); 5239441Smsmithstatic int comc_ischar(void); 53149213Siedowsestatic int comc_parsespeed(const char *string); 54149213Siedowsestatic void comc_setup(int speed); 55149213Siedowsestatic int comc_speed_set(struct env_var *ev, int flags, 56149213Siedowse const void *value); 5738465Smsmith 5840211Speterstatic int comc_started; 59149213Siedowsestatic int comc_curspeed; 6040211Speter 6138465Smsmithstruct console comconsole = { 6238465Smsmith "comconsole", 6341285Srnordier "serial port", 6438465Smsmith 0, 6538465Smsmith comc_probe, 6638465Smsmith comc_init, 6739441Smsmith comc_putchar, 6839441Smsmith comc_getchar, 6939441Smsmith comc_ischar 7038465Smsmith}; 7138465Smsmith 7238465Smsmithstatic void 7338465Smsmithcomc_probe(struct console *cp) 7438465Smsmith{ 75149213Siedowse char speedbuf[16]; 76149213Siedowse char *cons, *speedenv; 77149213Siedowse int speed; 78149213Siedowse 7938465Smsmith /* XXX check the BIOS equipment list? */ 8038465Smsmith cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); 81149213Siedowse 82149213Siedowse if (comc_curspeed == 0) { 83149213Siedowse comc_curspeed = COMSPEED; 84149213Siedowse /* 85149213Siedowse * Assume that the speed was set by an earlier boot loader if 86149213Siedowse * comconsole is already the preferred console. 87149213Siedowse */ 88149213Siedowse cons = getenv("console"); 89149213Siedowse if ((cons != NULL && strcmp(cons, comconsole.c_name) == 0) || 90149213Siedowse getenv("boot_multicons") != NULL) { 91149213Siedowse comc_curspeed = comc_getspeed(); 92149213Siedowse } 93149213Siedowse speedenv = getenv("comconsole_speed"); 94149213Siedowse if (speedenv != NULL) { 95149213Siedowse speed = comc_parsespeed(speedenv); 96149213Siedowse if (speed > 0) 97149213Siedowse comc_curspeed = speed; 98149213Siedowse } 99149213Siedowse 100149213Siedowse sprintf(speedbuf, "%d", comc_curspeed); 101149213Siedowse unsetenv("comconsole_speed"); 102149213Siedowse env_setenv("comconsole_speed", EV_VOLATILE, speedbuf, comc_speed_set, 103149213Siedowse env_nounset); 104149213Siedowse } 10538465Smsmith} 10638465Smsmith 10738465Smsmithstatic int 10838465Smsmithcomc_init(int arg) 10938465Smsmith{ 11040211Speter if (comc_started && arg == 0) 11140211Speter return 0; 11240211Speter comc_started = 1; 11340211Speter 114149213Siedowse comc_setup(comc_curspeed); 11540211Speter 11640211Speter return(0); 11738465Smsmith} 11838465Smsmith 11939441Smsmithstatic void 12039441Smsmithcomc_putchar(int c) 12139441Smsmith{ 12241285Srnordier int wait; 12341285Srnordier 12441285Srnordier for (wait = COMC_TXWAIT; wait > 0; wait--) 12541285Srnordier if (inb(COMPORT + com_lsr) & LSR_TXRDY) { 12664187Sjhb outb(COMPORT + com_data, (u_char)c); 12741285Srnordier break; 12841285Srnordier } 12939441Smsmith} 13039441Smsmith 13138465Smsmithstatic int 13239441Smsmithcomc_getchar(void) 13338465Smsmith{ 13441285Srnordier return(comc_ischar() ? inb(COMPORT + com_data) : -1); 13538465Smsmith} 13639441Smsmith 13739441Smsmithstatic int 13839441Smsmithcomc_ischar(void) 13939441Smsmith{ 14041285Srnordier return(inb(COMPORT + com_lsr) & LSR_RXRDY); 14139441Smsmith} 142149213Siedowse 143149213Siedowsestatic int 144149213Siedowsecomc_speed_set(struct env_var *ev, int flags, const void *value) 145149213Siedowse{ 146149213Siedowse int speed; 147149213Siedowse 148149213Siedowse if (value == NULL || (speed = comc_parsespeed(value)) <= 0) { 149149213Siedowse printf("Invalid speed\n"); 150149213Siedowse return (CMD_ERROR); 151149213Siedowse } 152149213Siedowse 153149213Siedowse if (comc_started && comc_curspeed != speed) 154149213Siedowse comc_setup(speed); 155149213Siedowse 156149213Siedowse env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 157149213Siedowse 158149213Siedowse return (CMD_OK); 159149213Siedowse} 160149213Siedowse 161149213Siedowsestatic void 162149213Siedowsecomc_setup(int speed) 163149213Siedowse{ 164149213Siedowse 165149213Siedowse comc_curspeed = speed; 166149213Siedowse 167149213Siedowse outb(COMPORT + com_cfcr, CFCR_DLAB | COMC_FMT); 168149213Siedowse outb(COMPORT + com_dlbl, COMC_BPS(speed) & 0xff); 169149213Siedowse outb(COMPORT + com_dlbh, COMC_BPS(speed) >> 8); 170149213Siedowse outb(COMPORT + com_cfcr, COMC_FMT); 171149213Siedowse outb(COMPORT + com_mcr, MCR_RTS | MCR_DTR); 172149213Siedowse 173149213Siedowse do 174149213Siedowse inb(COMPORT + com_data); 175149213Siedowse while (inb(COMPORT + com_lsr) & LSR_RXRDY); 176149213Siedowse} 177149213Siedowse 178149213Siedowsestatic int 179149213Siedowsecomc_parsespeed(const char *speedstr) 180149213Siedowse{ 181149213Siedowse char *p; 182149213Siedowse int speed; 183149213Siedowse 184149213Siedowse speed = strtol(speedstr, &p, 0); 185149213Siedowse if (p == speedstr || *p != '\0' || speed <= 0) 186149213Siedowse return (-1); 187149213Siedowse 188149213Siedowse return (speed); 189149213Siedowse} 190149213Siedowse 191149213Siedowsestatic int 192149213Siedowsecomc_getspeed(void) 193149213Siedowse{ 194149213Siedowse u_int divisor; 195149213Siedowse u_char dlbh; 196149213Siedowse u_char dlbl; 197149213Siedowse u_char cfcr; 198149213Siedowse 199149213Siedowse cfcr = inb(COMPORT + com_cfcr); 200149213Siedowse outb(COMPORT + com_cfcr, CFCR_DLAB | cfcr); 201149213Siedowse 202149213Siedowse dlbl = inb(COMPORT + com_dlbl); 203149213Siedowse dlbh = inb(COMPORT + com_dlbh); 204149213Siedowse 205149213Siedowse outb(COMPORT + com_cfcr, cfcr); 206149213Siedowse 207149213Siedowse divisor = dlbh << 8 | dlbl; 208149213Siedowse 209149213Siedowse /* XXX there should be more sanity checking. */ 210149213Siedowse if (divisor == 0) 211149213Siedowse return (COMSPEED); 212149213Siedowse return (COMC_DIV2BPS(divisor)); 213149213Siedowse} 214