2010-08-02 13:17:31 +04:00
# include "boot.h"
# define DEFAULT_SERIAL_PORT 0x3f8 /* ttyS0 */
# define DLAB 0x80
# define TXR 0 /* Transmit register (WRITE) */
# define RXR 0 /* Receive register (READ) */
# define IER 1 /* Interrupt Enable */
# define IIR 2 /* Interrupt ID */
# define FCR 2 /* FIFO control */
# define LCR 3 /* Line control */
# define MCR 4 /* Modem control */
# define LSR 5 /* Line Status */
# define MSR 6 /* Modem Status */
# define DLL 0 /* Divisor Latch Low */
# define DLH 1 /* Divisor latch High */
# define DEFAULT_BAUD 9600
static void early_serial_init ( int port , int baud )
{
unsigned char c ;
unsigned divisor ;
outb ( 0x3 , port + LCR ) ; /* 8n1 */
outb ( 0 , port + IER ) ; /* no interrupt */
outb ( 0 , port + FCR ) ; /* no fifo */
outb ( 0x3 , port + MCR ) ; /* DTR + RTS */
divisor = 115200 / baud ;
c = inb ( port + LCR ) ;
outb ( c | DLAB , port + LCR ) ;
outb ( divisor & 0xff , port + DLL ) ;
outb ( ( divisor > > 8 ) & 0xff , port + DLH ) ;
outb ( c & ~ DLAB , port + LCR ) ;
early_serial_base = port ;
}
static void parse_earlyprintk ( void )
{
int baud = DEFAULT_BAUD ;
char arg [ 32 ] ;
int pos = 0 ;
int port = 0 ;
if ( cmdline_find_option ( " earlyprintk " , arg , sizeof arg ) > 0 ) {
char * e ;
if ( ! strncmp ( arg , " serial " , 6 ) ) {
port = DEFAULT_SERIAL_PORT ;
pos + = 6 ;
}
if ( arg [ pos ] = = ' , ' )
pos + + ;
2010-08-30 05:13:10 +04:00
/*
* make sure we have
* " serial,0x3f8,115200 "
* " serial,ttyS0,115200 "
* " ttyS0,115200 "
*/
if ( pos = = 7 & & ! strncmp ( arg + pos , " 0x " , 2 ) ) {
port = simple_strtoull ( arg + pos , & e , 16 ) ;
if ( port = = 0 | | arg + pos = = e )
port = DEFAULT_SERIAL_PORT ;
else
pos = e - arg ;
} else if ( ! strncmp ( arg + pos , " ttyS " , 4 ) ) {
2010-08-02 13:17:31 +04:00
static const int bases [ ] = { 0x3f8 , 0x2f8 } ;
int idx = 0 ;
2014-12-31 10:12:38 +03:00
/* += strlen("ttyS"); */
pos + = 4 ;
2010-08-02 13:17:31 +04:00
if ( arg [ pos + + ] = = ' 1 ' )
idx = 1 ;
port = bases [ idx ] ;
}
if ( arg [ pos ] = = ' , ' )
pos + + ;
baud = simple_strtoull ( arg + pos , & e , 0 ) ;
if ( baud = = 0 | | arg + pos = = e )
baud = DEFAULT_BAUD ;
}
if ( port )
early_serial_init ( port , baud ) ;
}
# define BASE_BAUD (1843200 / 16)
static unsigned int probe_baud ( int port )
{
unsigned char lcr , dll , dlh ;
unsigned int quot ;
lcr = inb ( port + LCR ) ;
outb ( lcr | DLAB , port + LCR ) ;
dll = inb ( port + DLL ) ;
dlh = inb ( port + DLH ) ;
outb ( lcr , port + LCR ) ;
quot = ( dlh < < 8 ) | dll ;
return BASE_BAUD / quot ;
}
static void parse_console_uart8250 ( void )
{
char optstr [ 64 ] , * options ;
int baud = DEFAULT_BAUD ;
int port = 0 ;
/*
* console = uart8250 , io , 0x3f8 , 115200 n8
* need to make sure it is last one console !
*/
if ( cmdline_find_option ( " console " , optstr , sizeof optstr ) < = 0 )
return ;
options = optstr ;
if ( ! strncmp ( options , " uart8250,io, " , 12 ) )
port = simple_strtoull ( options + 12 , & options , 0 ) ;
else if ( ! strncmp ( options , " uart,io, " , 8 ) )
port = simple_strtoull ( options + 8 , & options , 0 ) ;
else
return ;
if ( options & & ( options [ 0 ] = = ' , ' ) )
baud = simple_strtoull ( options + 1 , & options , 0 ) ;
else
baud = probe_baud ( port ) ;
if ( port )
early_serial_init ( port , baud ) ;
}
void console_init ( void )
{
parse_earlyprintk ( ) ;
if ( ! early_serial_base )
parse_console_uart8250 ( ) ;
}