2005-04-16 15:20:36 -07:00
/* $Id: promcon.c,v 1.17 2000/07/26 23:02:52 davem Exp $
* Console driver utilizing PROM sun terminal emulation
*
* Copyright ( C ) 1998 Eddie C . Dost ( ecd @ skynet . be )
* Copyright ( C ) 1998 Jakub Jelinek ( jj @ ultra . linux . cz )
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/console.h>
# include <linux/vt_kern.h>
# include <linux/selection.h>
# include <linux/fb.h>
# include <linux/init.h>
# include <linux/kd.h>
# include <asm/oplib.h>
# include <asm/uaccess.h>
static short pw = 80 - 1 , ph = 34 - 1 ;
static short px , py ;
static unsigned long promcon_uni_pagedir [ 2 ] ;
extern u8 promfont_unicount [ ] ;
extern u16 promfont_unitable [ ] ;
# define PROMCON_COLOR 0
# if PROMCON_COLOR
# define inverted(s) ((((s) & 0x7700) == 0x0700) ? 0 : 1)
# else
# define inverted(s) (((s) & 0x0800) ? 1 : 0)
# endif
static __inline__ void
promcon_puts ( char * buf , int cnt )
{
prom_printf ( " %*.*s " , cnt , cnt , buf ) ;
}
static int
promcon_start ( struct vc_data * conp , char * b )
{
unsigned short * s = ( unsigned short * )
( conp - > vc_origin + py * conp - > vc_size_row + ( px < < 1 ) ) ;
u16 cs ;
cs = scr_readw ( s ) ;
if ( px = = pw ) {
unsigned short * t = s - 1 ;
u16 ct = scr_readw ( t ) ;
if ( inverted ( cs ) & & inverted ( ct ) )
return sprintf ( b , " \b \033 [7m%c \b \033 [@%c \033 [m " , cs ,
ct ) ;
else if ( inverted ( cs ) )
return sprintf ( b , " \b \033 [7m%c \033 [m \b \033 [@%c " , cs ,
ct ) ;
else if ( inverted ( ct ) )
return sprintf ( b , " \b %c \b \033 [@ \033 [7m%c \033 [m " , cs ,
ct ) ;
else
return sprintf ( b , " \b %c \b \033 [@%c " , cs , ct ) ;
}
if ( inverted ( cs ) )
return sprintf ( b , " \033 [7m%c \033 [m \b " , cs ) ;
else
return sprintf ( b , " %c \b " , cs ) ;
}
static int
promcon_end ( struct vc_data * conp , char * b )
{
unsigned short * s = ( unsigned short * )
( conp - > vc_origin + py * conp - > vc_size_row + ( px < < 1 ) ) ;
char * p = b ;
u16 cs ;
b + = sprintf ( b , " \033 [%d;%dH " , py + 1 , px + 1 ) ;
cs = scr_readw ( s ) ;
if ( px = = pw ) {
unsigned short * t = s - 1 ;
u16 ct = scr_readw ( t ) ;
if ( inverted ( cs ) & & inverted ( ct ) )
b + = sprintf ( b , " \b %c \b \033 [@ \033 [7m%c \033 [m " , cs , ct ) ;
else if ( inverted ( cs ) )
b + = sprintf ( b , " \b %c \b \033 [@%c " , cs , ct ) ;
else if ( inverted ( ct ) )
b + = sprintf ( b , " \b \033 [7m%c \b \033 [@%c \033 [m " , cs , ct ) ;
else
b + = sprintf ( b , " \b \033 [7m%c \033 [m \b \033 [@%c " , cs , ct ) ;
return b - p ;
}
if ( inverted ( cs ) )
b + = sprintf ( b , " %c \b " , cs ) ;
else
b + = sprintf ( b , " \033 [7m%c \033 [m \b " , cs ) ;
return b - p ;
}
2006-06-26 00:27:16 -07:00
const char * promcon_startup ( void )
2005-04-16 15:20:36 -07:00
{
const char * display_desc = " PROM " ;
int node ;
char buf [ 40 ] ;
node = prom_getchild ( prom_root_node ) ;
node = prom_searchsiblings ( node , " options " ) ;
if ( prom_getproperty ( node , " screen-#columns " , buf , 40 ) ! = - 1 ) {
pw = simple_strtoul ( buf , NULL , 0 ) ;
if ( pw < 10 | | pw > 256 )
pw = 80 ;
pw - - ;
}
if ( prom_getproperty ( node , " screen-#rows " , buf , 40 ) ! = - 1 ) {
ph = simple_strtoul ( buf , NULL , 0 ) ;
if ( ph < 10 | | ph > 256 )
ph = 34 ;
ph - - ;
}
promcon_puts ( " \033 [H \033 [J " , 6 ) ;
return display_desc ;
}
2006-06-26 00:27:16 -07:00
static void
2005-04-16 15:20:36 -07:00
promcon_init_unimap ( struct vc_data * conp )
{
mm_segment_t old_fs = get_fs ( ) ;
struct unipair * p , * p1 ;
u16 * q ;
int i , j , k ;
p = kmalloc ( 256 * sizeof ( struct unipair ) , GFP_KERNEL ) ;
if ( ! p ) return ;
q = promfont_unitable ;
p1 = p ;
k = 0 ;
for ( i = 0 ; i < 256 ; i + + )
for ( j = promfont_unicount [ i ] ; j ; j - - ) {
p1 - > unicode = * q + + ;
p1 - > fontpos = i ;
p1 + + ;
k + + ;
}
set_fs ( KERNEL_DS ) ;
con_clear_unimap ( conp , NULL ) ;
con_set_unimap ( conp , k , p ) ;
con_protect_unimap ( conp , 1 ) ;
set_fs ( old_fs ) ;
kfree ( p ) ;
}
static void
promcon_init ( struct vc_data * conp , int init )
{
unsigned long p ;
conp - > vc_can_do_color = PROMCON_COLOR ;
if ( init ) {
conp - > vc_cols = pw + 1 ;
conp - > vc_rows = ph + 1 ;
}
p = * conp - > vc_uni_pagedir_loc ;
if ( conp - > vc_uni_pagedir_loc = = & conp - > vc_uni_pagedir | |
! - - conp - > vc_uni_pagedir_loc [ 1 ] )
con_free_unimap ( conp ) ;
conp - > vc_uni_pagedir_loc = promcon_uni_pagedir ;
promcon_uni_pagedir [ 1 ] + + ;
if ( ! promcon_uni_pagedir [ 0 ] & & p ) {
promcon_init_unimap ( conp ) ;
}
if ( ! init ) {
if ( conp - > vc_cols ! = pw + 1 | | conp - > vc_rows ! = ph + 1 )
vc_resize ( conp , pw + 1 , ph + 1 ) ;
}
}
static void
promcon_deinit ( struct vc_data * conp )
{
/* When closing the last console, reset video origin */
if ( ! - - promcon_uni_pagedir [ 1 ] )
con_free_unimap ( conp ) ;
conp - > vc_uni_pagedir_loc = & conp - > vc_uni_pagedir ;
con_set_default_unimap ( conp ) ;
}
static int
promcon_switch ( struct vc_data * conp )
{
return 1 ;
}
static unsigned short *
promcon_repaint_line ( unsigned short * s , unsigned char * buf , unsigned char * * bp )
{
int cnt = pw + 1 ;
int attr = - 1 ;
unsigned char * b = * bp ;
while ( cnt - - ) {
u16 c = scr_readw ( s ) ;
if ( attr ! = inverted ( c ) ) {
attr = inverted ( c ) ;
if ( attr ) {
strcpy ( b , " \033 [7m " ) ;
b + = 4 ;
} else {
strcpy ( b , " \033 [m " ) ;
b + = 3 ;
}
}
* b + + = c ;
s + + ;
if ( b - buf > = 224 ) {
promcon_puts ( buf , b - buf ) ;
b = buf ;
}
}
* bp = b ;
return s ;
}
static void
promcon_putcs ( struct vc_data * conp , const unsigned short * s ,
int count , int y , int x )
{
unsigned char buf [ 256 ] , * b = buf ;
unsigned short attr = scr_readw ( s ) ;
unsigned char save ;
int i , last = 0 ;
if ( console_blanked )
return ;
if ( count < = 0 )
return ;
b + = promcon_start ( conp , b ) ;
if ( x + count > = pw + 1 ) {
if ( count = = 1 ) {
x - = 1 ;
save = scr_readw ( ( unsigned short * ) ( conp - > vc_origin
+ y * conp - > vc_size_row
+ ( x < < 1 ) ) ) ;
if ( px ! = x | | py ! = y ) {
b + = sprintf ( b , " \033 [%d;%dH " , y + 1 , x + 1 ) ;
px = x ;
py = y ;
}
if ( inverted ( attr ) )
b + = sprintf ( b , " \033 [7m%c \033 [m " , scr_readw ( s + + ) ) ;
else
b + = sprintf ( b , " %c " , scr_readw ( s + + ) ) ;
strcpy ( b , " \b \033 [@ " ) ;
b + = 4 ;
if ( inverted ( save ) )
b + = sprintf ( b , " \033 [7m%c \033 [m " , save ) ;
else
b + = sprintf ( b , " %c " , save ) ;
px + + ;
b + = promcon_end ( conp , b ) ;
promcon_puts ( buf , b - buf ) ;
return ;
} else {
last = 1 ;
count = pw - x - 1 ;
}
}
if ( inverted ( attr ) ) {
strcpy ( b , " \033 [7m " ) ;
b + = 4 ;
}
if ( px ! = x | | py ! = y ) {
b + = sprintf ( b , " \033 [%d;%dH " , y + 1 , x + 1 ) ;
px = x ;
py = y ;
}
for ( i = 0 ; i < count ; i + + ) {
if ( b - buf > = 224 ) {
promcon_puts ( buf , b - buf ) ;
b = buf ;
}
* b + + = scr_readw ( s + + ) ;
}
px + = count ;
if ( last ) {
save = scr_readw ( s + + ) ;
b + = sprintf ( b , " %c \b \033 [@%c " , scr_readw ( s + + ) , save ) ;
px + + ;
}
if ( inverted ( attr ) ) {
strcpy ( b , " \033 [m " ) ;
b + = 3 ;
}
b + = promcon_end ( conp , b ) ;
promcon_puts ( buf , b - buf ) ;
}
static void
promcon_putc ( struct vc_data * conp , int c , int y , int x )
{
unsigned short s ;
if ( console_blanked )
return ;
scr_writew ( c , & s ) ;
promcon_putcs ( conp , & s , 1 , y , x ) ;
}
static void
promcon_clear ( struct vc_data * conp , int sy , int sx , int height , int width )
{
unsigned char buf [ 256 ] , * b = buf ;
int i , j ;
if ( console_blanked )
return ;
b + = promcon_start ( conp , b ) ;
if ( ! sx & & width = = pw + 1 ) {
if ( ! sy & & height = = ph + 1 ) {
strcpy ( b , " \033 [H \033 [J " ) ;
b + = 6 ;
b + = promcon_end ( conp , b ) ;
promcon_puts ( buf , b - buf ) ;
return ;
} else if ( sy + height = = ph + 1 ) {
b + = sprintf ( b , " \033 [%dH \033 [J " , sy + 1 ) ;
b + = promcon_end ( conp , b ) ;
promcon_puts ( buf , b - buf ) ;
return ;
}
b + = sprintf ( b , " \033 [%dH " , sy + 1 ) ;
for ( i = 1 ; i < height ; i + + ) {
strcpy ( b , " \033 [K \n " ) ;
b + = 4 ;
}
strcpy ( b , " \033 [K " ) ;
b + = 3 ;
b + = promcon_end ( conp , b ) ;
promcon_puts ( buf , b - buf ) ;
return ;
} else if ( sx + width = = pw + 1 ) {
b + = sprintf ( b , " \033 [%d;%dH " , sy + 1 , sx + 1 ) ;
for ( i = 1 ; i < height ; i + + ) {
strcpy ( b , " \033 [K \n " ) ;
b + = 4 ;
}
strcpy ( b , " \033 [K " ) ;
b + = 3 ;
b + = promcon_end ( conp , b ) ;
promcon_puts ( buf , b - buf ) ;
return ;
}
for ( i = sy + 1 ; i < = sy + height ; i + + ) {
b + = sprintf ( b , " \033 [%d;%dH " , i , sx + 1 ) ;
for ( j = 0 ; j < width ; j + + )
* b + + = ' ' ;
if ( b - buf + width > = 224 ) {
promcon_puts ( buf , b - buf ) ;
b = buf ;
}
}
b + = promcon_end ( conp , b ) ;
promcon_puts ( buf , b - buf ) ;
}
static void
promcon_bmove ( struct vc_data * conp , int sy , int sx , int dy , int dx ,
int height , int width )
{
char buf [ 256 ] , * b = buf ;
if ( console_blanked )
return ;
b + = promcon_start ( conp , b ) ;
if ( sy = = dy & & height = = 1 ) {
if ( dx > sx & & dx + width = = conp - > vc_cols )
b + = sprintf ( b , " \033 [%d;%dH \033 [%d@ \033 [%d;%dH " ,
sy + 1 , sx + 1 , dx - sx , py + 1 , px + 1 ) ;
else if ( dx < sx & & sx + width = = conp - > vc_cols )
b + = sprintf ( b , " \033 [%d;%dH \033 [%dP \033 [%d;%dH " ,
dy + 1 , dx + 1 , sx - dx , py + 1 , px + 1 ) ;
b + = promcon_end ( conp , b ) ;
promcon_puts ( buf , b - buf ) ;
return ;
}
/*
* FIXME : What to do here ? ? ?
* Current console . c should not call it like that ever .
*/
prom_printf ( " \033 [7mFIXME: bmove not handled \033 [m \n " ) ;
}
static void
promcon_cursor ( struct vc_data * conp , int mode )
{
char buf [ 32 ] , * b = buf ;
switch ( mode ) {
case CM_ERASE :
break ;
case CM_MOVE :
case CM_DRAW :
b + = promcon_start ( conp , b ) ;
if ( px ! = conp - > vc_x | | py ! = conp - > vc_y ) {
px = conp - > vc_x ;
py = conp - > vc_y ;
b + = sprintf ( b , " \033 [%d;%dH " , py + 1 , px + 1 ) ;
}
promcon_puts ( buf , b - buf ) ;
break ;
}
}
static int
promcon_blank ( struct vc_data * conp , int blank , int mode_switch )
{
if ( blank ) {
promcon_puts ( " \033 [H \033 [J \033 [7m \033 [m \b " , 15 ) ;
return 0 ;
} else {
/* Let console.c redraw */
return 1 ;
}
}
static int
promcon_scroll ( struct vc_data * conp , int t , int b , int dir , int count )
{
unsigned char buf [ 256 ] , * p = buf ;
unsigned short * s ;
int i ;
if ( console_blanked )
return 0 ;
p + = promcon_start ( conp , p ) ;
switch ( dir ) {
case SM_UP :
if ( b = = ph + 1 ) {
p + = sprintf ( p , " \033 [%dH \033 [%dM " , t + 1 , count ) ;
px = 0 ;
py = t ;
p + = promcon_end ( conp , p ) ;
promcon_puts ( buf , p - buf ) ;
break ;
}
s = ( unsigned short * ) ( conp - > vc_origin
+ ( t + count ) * conp - > vc_size_row ) ;
p + = sprintf ( p , " \033 [%dH " , t + 1 ) ;
for ( i = t ; i < b - count ; i + + )
s = promcon_repaint_line ( s , buf , & p ) ;
for ( ; i < b - 1 ; i + + ) {
strcpy ( p , " \033 [K \n " ) ;
p + = 4 ;
if ( p - buf > = 224 ) {
promcon_puts ( buf , p - buf ) ;
p = buf ;
}
}
strcpy ( p , " \033 [K " ) ;
p + = 3 ;
p + = promcon_end ( conp , p ) ;
promcon_puts ( buf , p - buf ) ;
break ;
case SM_DOWN :
if ( b = = ph + 1 ) {
p + = sprintf ( p , " \033 [%dH \033 [%dL " , t + 1 , count ) ;
px = 0 ;
py = t ;
p + = promcon_end ( conp , p ) ;
promcon_puts ( buf , p - buf ) ;
break ;
}
s = ( unsigned short * ) ( conp - > vc_origin + t * conp - > vc_size_row ) ;
p + = sprintf ( p , " \033 [%dH " , t + 1 ) ;
for ( i = t ; i < t + count ; i + + ) {
strcpy ( p , " \033 [K \n " ) ;
p + = 4 ;
if ( p - buf > = 224 ) {
promcon_puts ( buf , p - buf ) ;
p = buf ;
}
}
for ( ; i < b ; i + + )
s = promcon_repaint_line ( s , buf , & p ) ;
p + = promcon_end ( conp , p ) ;
promcon_puts ( buf , p - buf ) ;
break ;
}
return 0 ;
}
# if !(PROMCON_COLOR)
static u8 promcon_build_attr ( struct vc_data * conp , u8 _color , u8 _intensity , u8 _blink , u8 _underline , u8 _reverse )
{
return ( _reverse ) ? 0xf : 0x7 ;
}
# endif
/*
* The console ' switch ' structure for the VGA based console
*/
static int promcon_dummy ( void )
{
return 0 ;
}
# define DUMMY (void *) promcon_dummy
const struct consw prom_con = {
. owner = THIS_MODULE ,
. con_startup = promcon_startup ,
. con_init = promcon_init ,
. con_deinit = promcon_deinit ,
. con_clear = promcon_clear ,
. con_putc = promcon_putc ,
. con_putcs = promcon_putcs ,
. con_cursor = promcon_cursor ,
. con_scroll = promcon_scroll ,
. con_bmove = promcon_bmove ,
. con_switch = promcon_switch ,
. con_blank = promcon_blank ,
. con_set_palette = DUMMY ,
. con_scrolldelta = DUMMY ,
# if !(PROMCON_COLOR)
. con_build_attr = promcon_build_attr ,
# endif
} ;
void __init prom_con_init ( void )
{
# ifdef CONFIG_DUMMY_CONSOLE
if ( conswitchp = = & dummy_con )
take_over_console ( & prom_con , 0 , MAX_NR_CONSOLES - 1 , 1 ) ;
else
# endif
if ( conswitchp = = & prom_con )
promcon_init_unimap ( vc_cons [ fg_console ] . d ) ;
}