diff options
Diffstat (limited to 'drivers/tty/vt/vt.c')
| -rw-r--r-- | drivers/tty/vt/vt.c | 152 | 
1 files changed, 122 insertions, 30 deletions
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 9a8e8c5a0c7..b33b00b386d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -735,7 +735,7 @@ static void visual_init(struct vc_data *vc, int num, int init)  	vc->vc_num = num;  	vc->vc_display_fg = &master_display_fg;  	vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; -	vc->vc_uni_pagedir = 0; +	vc->vc_uni_pagedir = NULL;  	vc->vc_hi_font_mask = 0;  	vc->vc_complement_mask = 0;  	vc->vc_can_do_color = 0; @@ -1164,6 +1164,8 @@ static void csi_J(struct vc_data *vc, int vpar)  			scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,  				    vc->vc_screenbuf_size >> 1);  			set_origin(vc); +			if (CON_IS_VISIBLE(vc)) +				update_screen(vc);  			/* fall through */  		case 2: /* erase whole display */  			count = vc->vc_cols * vc->vc_rows; @@ -1229,6 +1231,52 @@ static void default_attr(struct vc_data *vc)  	vc->vc_color = vc->vc_def_color;  } +struct rgb { u8 r; u8 g; u8 b; }; + +struct rgb rgb_from_256(int i) +{ +	struct rgb c; +	if (i < 8) {            /* Standard colours. */ +		c.r = i&1 ? 0xaa : 0x00; +		c.g = i&2 ? 0xaa : 0x00; +		c.b = i&4 ? 0xaa : 0x00; +	} else if (i < 16) { +		c.r = i&1 ? 0xff : 0x55; +		c.g = i&2 ? 0xff : 0x55; +		c.b = i&4 ? 0xff : 0x55; +	} else if (i < 232) {   /* 6x6x6 colour cube. */ +		c.r = (i - 16) / 36 * 85 / 2; +		c.g = (i - 16) / 6 % 6 * 85 / 2; +		c.b = (i - 16) % 6 * 85 / 2; +	} else                  /* Grayscale ramp. */ +		c.r = c.g = c.b = i * 10 - 2312; +	return c; +} + +static void rgb_foreground(struct vc_data *vc, struct rgb c) +{ +	u8 hue, max = c.r; +	if (c.g > max) +		max = c.g; +	if (c.b > max) +		max = c.b; +	hue = (c.r > max/2 ? 4 : 0) +	    | (c.g > max/2 ? 2 : 0) +	    | (c.b > max/2 ? 1 : 0); +	if (hue == 7 && max <= 0x55) +		hue = 0, vc->vc_intensity = 2; +	else +		vc->vc_intensity = (max > 0xaa) + 1; +	vc->vc_color = (vc->vc_color & 0xf0) | hue; +} + +static void rgb_background(struct vc_data *vc, struct rgb c) +{ +	/* For backgrounds, err on the dark side. */ +	vc->vc_color = (vc->vc_color & 0x0f) +		| (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3; +} +  /* console_lock is held */  static void csi_m(struct vc_data *vc)  { @@ -1300,21 +1348,55 @@ static void csi_m(struct vc_data *vc)  			case 27:  				vc->vc_reverse = 0;  				break; -			case 38: /* ANSI X3.64-1979 (SCO-ish?) -				  * Enables underscore, white foreground -				  * with white underscore (Linux - use -				  * default foreground). +			case 38: /* ITU T.416 +				  * Higher colour modes. +				  * They break the usual properties of SGR codes +				  * and thus need to be detected and ignored by +				  * hand.  Strictly speaking, that standard also +				  * wants : rather than ; as separators, contrary +				  * to ECMA-48, but no one produces such codes +				  * and almost no one accepts them.  				  */ -				vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); -				vc->vc_underline = 1; +				i++; +				if (i > vc->vc_npar) +					break; +				if (vc->vc_par[i] == 5 &&  /* 256 colours */ +				    i < vc->vc_npar) {     /* ubiquitous */ +					i++; +					rgb_foreground(vc, +						rgb_from_256(vc->vc_par[i])); +				} else if (vc->vc_par[i] == 2 &&  /* 24 bit */ +				           i <= vc->vc_npar + 3) {/* extremely rare */ +					struct rgb c = {r:vc->vc_par[i+1], +							g:vc->vc_par[i+2], +							b:vc->vc_par[i+3]}; +					rgb_foreground(vc, c); +					i += 3; +				} +				/* Subcommands 3 (CMY) and 4 (CMYK) are so insane +				 * there's no point in supporting them. +				 */  				break; -			case 39: /* ANSI X3.64-1979 (SCO-ish?) -				  * Disable underline option. -				  * Reset colour to default? It did this -				  * before... -				  */ +			case 48: +				i++; +				if (i > vc->vc_npar) +					break; +				if (vc->vc_par[i] == 5 &&  /* 256 colours */ +				    i < vc->vc_npar) { +					i++; +					rgb_background(vc, +						rgb_from_256(vc->vc_par[i])); +				} else if (vc->vc_par[i] == 2 && /* 24 bit */ +				           i <= vc->vc_npar + 3) { +					struct rgb c = {r:vc->vc_par[i+1], +							g:vc->vc_par[i+2], +							b:vc->vc_par[i+3]}; +					rgb_background(vc, c); +					i += 3; +				} +				break; +			case 39:  				vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0); -				vc->vc_underline = 0;  				break;  			case 49:  				vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f); @@ -1579,9 +1661,9 @@ static void restore_cur(struct vc_data *vc)  	vc->vc_need_wrap = 0;  } -enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, +enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,  	EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, -	ESpalette }; +	ESpalette, ESosc };  /* console_lock is held (except via vc_init()) */  static void reset_terminal(struct vc_data *vc, int do_clear) @@ -1641,11 +1723,15 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)  	 *  Control characters can be used in the _middle_  	 *  of an escape sequence.  	 */ +	if (vc->vc_state == ESosc && c>=8 && c<=13) /* ... except for OSC */ +		return;  	switch (c) {  	case 0:  		return;  	case 7: -		if (vc->vc_bell_duration) +		if (vc->vc_state == ESosc) +			vc->vc_state = ESnormal; +		else if (vc->vc_bell_duration)  			kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);  		return;  	case 8: @@ -1756,7 +1842,9 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)  		} else if (c=='R') {   /* reset palette */  			reset_palette(vc);  			vc->vc_state = ESnormal; -		} else +		} else if (c>='0' && c<='9') +			vc->vc_state = ESosc; +		else  			vc->vc_state = ESnormal;  		return;  	case ESpalette: @@ -1796,9 +1884,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)  			vc->vc_par[vc->vc_npar] *= 10;  			vc->vc_par[vc->vc_npar] += c - '0';  			return; -		} else -			vc->vc_state = ESgotpars; -	case ESgotpars: +		}  		vc->vc_state = ESnormal;  		switch(c) {  		case 'h': @@ -2012,6 +2098,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)  			vc->vc_translate = set_translate(vc->vc_G1_charset, vc);  		vc->vc_state = ESnormal;  		return; +	case ESosc: +		return;  	default:  		vc->vc_state = ESnormal;  	} @@ -3138,8 +3226,7 @@ int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt  	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {  		con_back = ®istered_con_driver[i]; -		if (con_back->con && -		    !(con_back->flag & CON_DRIVER_FLAG_MODULE)) { +		if (con_back->con && con_back->con != csw) {  			defcsw = con_back->con;  			retval = 0;  			break; @@ -3244,6 +3331,7 @@ static int vt_unbind(struct con_driver *con)  {  	const struct consw *csw = NULL;  	int i, more = 1, first = -1, last = -1, deflt = 0; +	int ret;   	if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||  	    con_is_graphics(con->con, con->first, con->last)) @@ -3269,8 +3357,10 @@ static int vt_unbind(struct con_driver *con)  		if (first != -1) {  			console_lock(); -			do_unbind_con_driver(csw, first, last, deflt); +			ret = do_unbind_con_driver(csw, first, last, deflt);  			console_unlock(); +			if (ret != 0) +				return ret;  		}  		first = -1; @@ -3557,17 +3647,20 @@ err:   */  int do_unregister_con_driver(const struct consw *csw)  { -	int i, retval = -ENODEV; +	int i;  	/* cannot unregister a bound driver */  	if (con_is_bound(csw)) -		goto err; +		return -EBUSY; + +	if (csw == conswitchp) +		return -EINVAL;  	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {  		struct con_driver *con_driver = ®istered_con_driver[i];  		if (con_driver->con == csw && -		    con_driver->flag & CON_DRIVER_FLAG_MODULE) { +		    con_driver->flag & CON_DRIVER_FLAG_INIT) {  			vtconsole_deinit_device(con_driver);  			device_destroy(vtconsole_class,  				       MKDEV(0, con_driver->node)); @@ -3578,12 +3671,11 @@ int do_unregister_con_driver(const struct consw *csw)  			con_driver->flag = 0;  			con_driver->first = 0;  			con_driver->last = 0; -			retval = 0; -			break; +			return 0;  		}  	} -err: -	return retval; + +	return -ENODEV;  }  EXPORT_SYMBOL_GPL(do_unregister_con_driver);  | 
