boot_console.c revision ae115bc77f6fcde83175c75b4206dc2e50747966
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/archsystm.h>
#include <sys/boot_console.h>
#include "boot_serial.h"
#include "boot_vga.h"
#if defined(_BOOT)
#include "../dboot/dboot_xboot.h"
#else
#include <sys/bootconf.h>
static char *usbser_buf;
static char *usbser_cur;
#endif
static int cons_color = CONS_COLOR;
int console = CONS_SCREEN_TEXT;
/* or CONS_TTYA, CONS_TTYB */
static int serial_ischar(void);
static int serial_getchar(void);
static void serial_putchar(int);
static void serial_adjust_prop(void);
/* Clear the screen and initialize VIDEO, XPOS and YPOS. */
static void
clear_screen(void)
{
/*
* XXX should set vga mode so we don't depend on the
* state left by the boot loader
*/
vga_setpos(0, 0);
}
/* Put the character C on the screen. */
static void
screen_putchar(int c)
{
switch (c) {
case '\t':
if (col == VGA_TEXT_COLS)
col = 79;
break;
case '\r':
vga_setpos(row, 0);
break;
case '\b':
if (col > 0)
break;
case '\n':
else
break;
default:
vga_drawc(c, cons_color);
else {
vga_setpos(row, 0);
}
break;
}
}
/* serial port stuff */
static int port;
static void
serial_init(void)
{
switch (console) {
case CONS_TTYA:
port = 0x3f8;
break;
case CONS_TTYB:
port = 0x2f8;
break;
}
/*
* 82510 chip is present
*/
} else {
/*
* set the UART in FIFO mode if it has FIFO buffers.
* use 16550 fifo reset sequence specified in NS
* application note. disable fifos until chip is
* initialized.
*/
/*
* no fifo buffers so disable fifos.
* this is true for 8250's
*/
}
}
/* disable interrupts */
/* adjust setting based on tty properties */
#if defined(_BOOT)
/*
* Do a full reset to match console behavior.
* 0x1B + c - reset everything
*/
serial_putchar(0x1B);
serial_putchar('c');
#endif
}
#define SKIP(p, c) \
while (*(p) != 0 && *p != (c)) \
++(p); \
if (*(p) == (c)) \
++(p);
/*
* find a tty mode property either from cmdline or from boot properties
*/
static char *
get_mode_value(char *name)
{
char *p;
/*
* when specified on boot line it looks like "name" "="....
*/
if (p == NULL)
return (NULL);
SKIP(p, '=');
return (p);
}
#if defined(_BOOT)
return (NULL);
#else
/*
* if we're running in the full kernel we check the bootenv.rc settings
*/
{
static char propval[20];
propval[0] = 0;
return (NULL);
return (propval);
}
#endif
}
/*
* adjust serial port based on properties
* These come either from the cmdline or from boot properties.
*/
static void
serial_adjust_prop(void)
{
char propname[20];
char *propval;
char *p;
propval = "9600,8,n,1,-";
/* property is of the form: "9600,8,n,1,-" */
p = propval;
if (MATCHES(p, "110,"))
else if (MATCHES(p, "150,"))
else if (MATCHES(p, "300,"))
else if (MATCHES(p, "600,"))
else if (MATCHES(p, "1200,"))
else if (MATCHES(p, "2400,"))
else if (MATCHES(p, "4800,"))
else if (MATCHES(p, "19200,"))
else if (MATCHES(p, "38400,"))
else if (MATCHES(p, "57600,"))
else if (MATCHES(p, "115200,"))
else {
SKIP(p, ',');
}
switch (*p) {
case '5':
++p;
break;
case '6':
++p;
break;
case '7':
++p;
break;
case '8':
++p;
default:
break;
}
SKIP(p, ',');
switch (*p) {
case 'n':
lcr |= PARITY_NONE;
++p;
break;
case 'o':
lcr |= PARITY_ODD;
++p;
break;
case 'e':
++p;
default:
lcr |= PARITY_EVEN;
break;
}
SKIP(p, ',');
switch (*p) {
case '1':
/* STOP1 is 0 */
++p;
break;
default:
break;
}
/* set parity bits */
propval = "false";
mcr = 0;
/* set modem control bits */
}
void
bcons_init(char *bootstr)
{
/*
* If no console device specified, default to text.
* Remember what was specified for second phase.
*/
if (console == CONS_INVALID)
switch (console) {
case CONS_TTYA:
case CONS_TTYB:
serial_init();
break;
case CONS_SCREEN_TEXT:
default:
#if defined(_BOOT)
clear_screen(); /* clears the grub screen */
#endif
kb_init();
break;
}
}
/*
* 2nd part of console initialization.
* In the kernel (ie. fakebop), this can be used only to switch to
* using a serial port instead of screen based on the contents
* of the bootenv.rc file.
*/
/*ARGSUSED*/
void
{
#if !defined(_BOOT)
int cons = CONS_INVALID;
if (consoledev) {
cons = CONS_USBSER;
}
cons = CONS_USBSER;
}
cons = CONS_USBSER;
}
if (cons == CONS_INVALID)
return;
return;
serial_init();
return;
}
/*
* USB serial -- we just collect data into a buffer
*/
if (cons == CONS_USBSER) {
extern void *usbser_init(size_t);
}
#endif /* _BOOT */
}
#if !defined(_BOOT)
static void
usbser_putchar(int c)
{
*usbser_cur++ = c;
}
#endif /* _BOOT */
static void
serial_putchar(int c)
{
int checks = 10000;
;
}
static int
serial_getchar(void)
{
while (serial_ischar() == 0)
;
SERIAL_PARITY | SERIAL_OVERRUN)) {
if (lsr & SERIAL_OVERRUN) {
} else {
/* Toss the garbage */
return (0);
}
}
}
static int
serial_ischar(void)
{
}
static void
_doputchar(int c)
{
switch (console) {
case CONS_TTYA:
case CONS_TTYB:
serial_putchar(c);
return;
case CONS_SCREEN_TEXT:
screen_putchar(c);
return;
#if !defined(_BOOT)
case CONS_USBSER:
usbser_putchar(c);
return;
#endif /* _BOOT */
}
}
void
bcons_putchar(int c)
{
static int bhcharpos = 0;
if (c == '\t') {
do {
_doputchar(' ');
} while (++bhcharpos % 8);
return;
} else if (c == '\n' || c == '\r') {
bhcharpos = 0;
_doputchar('\r');
_doputchar(c);
return;
} else if (c == '\b') {
if (bhcharpos)
bhcharpos--;
_doputchar(c);
return;
}
bhcharpos++;
_doputchar(c);
}
/*
* kernel character input functions
*/
int
bcons_getchar(void)
{
switch (console) {
case CONS_TTYA:
case CONS_TTYB:
return (serial_getchar());
default:
return (kb_getchar());
}
}
#if !defined(_BOOT)
int
bcons_ischar(void)
{
switch (console) {
case CONS_TTYA:
case CONS_TTYB:
return (serial_ischar());
default:
return (kb_ischar());
}
}
#endif /* _BOOT */