|  | @@ -288,7 +288,7 @@ static void fbcon_redraw ( struct fbcon *fbcon ) {
 | 
		
	
		
			
			| 288 | 288 |   */
 | 
		
	
		
			
			| 289 | 289 |  static void fbcon_clear ( struct fbcon *fbcon, unsigned int ypos ) {
 | 
		
	
		
			
			| 290 | 290 |  	struct fbcon_text_cell cell = {
 | 
		
	
		
			
			| 291 |  | -		.foreground = 0,
 | 
		
	
		
			
			|  | 291 | +		.foreground = fbcon->foreground,
 | 
		
	
		
			
			| 292 | 292 |  		.background = fbcon->background,
 | 
		
	
		
			
			| 293 | 293 |  		.character = ' ',
 | 
		
	
		
			
			| 294 | 294 |  	};
 | 
		
	
	
		
			
			|  | @@ -317,19 +317,40 @@ static void fbcon_clear ( struct fbcon *fbcon, unsigned int ypos ) {
 | 
		
	
		
			
			| 317 | 317 |  static void fbcon_scroll ( struct fbcon *fbcon ) {
 | 
		
	
		
			
			| 318 | 318 |  	size_t row_len;
 | 
		
	
		
			
			| 319 | 319 |  
 | 
		
	
		
			
			| 320 |  | -	/* If we are not yet at the bottom of the screen, just update
 | 
		
	
		
			
			| 321 |  | -	 * the cursor position.
 | 
		
	
		
			
			| 322 |  | -	 */
 | 
		
	
		
			
			| 323 |  | -	if ( fbcon->ypos < ( fbcon->character.height - 1 ) ) {
 | 
		
	
		
			
			| 324 |  | -		fbcon->ypos++;
 | 
		
	
		
			
			| 325 |  | -		return;
 | 
		
	
		
			
			| 326 |  | -	}
 | 
		
	
		
			
			|  | 320 | +	/* Sanity check */
 | 
		
	
		
			
			|  | 321 | +	assert ( fbcon->ypos == fbcon->character.height );
 | 
		
	
		
			
			| 327 | 322 |  
 | 
		
	
		
			
			| 328 |  | -	/* Otherwise, scroll up character array */
 | 
		
	
		
			
			|  | 323 | +	/* Scroll up character array */
 | 
		
	
		
			
			| 329 | 324 |  	row_len = ( fbcon->character.width * sizeof ( struct fbcon_text_cell ));
 | 
		
	
		
			
			| 330 | 325 |  	memmove_user ( fbcon->text.start, 0, fbcon->text.start, row_len,
 | 
		
	
		
			
			| 331 | 326 |  		       ( row_len * ( fbcon->character.height - 1 ) ) );
 | 
		
	
		
			
			| 332 | 327 |  	fbcon_clear ( fbcon, ( fbcon->character.height - 1 ) );
 | 
		
	
		
			
			|  | 328 | +
 | 
		
	
		
			
			|  | 329 | +	/* Update cursor position */
 | 
		
	
		
			
			|  | 330 | +	fbcon->ypos--;
 | 
		
	
		
			
			|  | 331 | +}
 | 
		
	
		
			
			|  | 332 | +
 | 
		
	
		
			
			|  | 333 | +/**
 | 
		
	
		
			
			|  | 334 | + * Draw character at cursor position
 | 
		
	
		
			
			|  | 335 | + *
 | 
		
	
		
			
			|  | 336 | + * @v fbcon		Frame buffer console
 | 
		
	
		
			
			|  | 337 | + * @v show_cursor	Show cursor
 | 
		
	
		
			
			|  | 338 | + */
 | 
		
	
		
			
			|  | 339 | +static void fbcon_draw_cursor ( struct fbcon *fbcon, int show_cursor ) {
 | 
		
	
		
			
			|  | 340 | +	struct fbcon_text_cell cell;
 | 
		
	
		
			
			|  | 341 | +	size_t offset;
 | 
		
	
		
			
			|  | 342 | +	uint32_t background;
 | 
		
	
		
			
			|  | 343 | +
 | 
		
	
		
			
			|  | 344 | +	offset = ( ( ( fbcon->ypos * fbcon->character.width ) + fbcon->xpos ) *
 | 
		
	
		
			
			|  | 345 | +		   sizeof ( cell ) );
 | 
		
	
		
			
			|  | 346 | +	copy_from_user ( &cell, fbcon->text.start, offset, sizeof ( cell ) );
 | 
		
	
		
			
			|  | 347 | +	if ( show_cursor ) {
 | 
		
	
		
			
			|  | 348 | +		background = cell.background;
 | 
		
	
		
			
			|  | 349 | +		cell.background = cell.foreground;
 | 
		
	
		
			
			|  | 350 | +		cell.foreground = ( ( background == FBCON_TRANSPARENT ) ?
 | 
		
	
		
			
			|  | 351 | +				    0 : background );
 | 
		
	
		
			
			|  | 352 | +	}
 | 
		
	
		
			
			|  | 353 | +	fbcon_draw_character ( fbcon, &cell, fbcon->xpos, fbcon->ypos );
 | 
		
	
		
			
			| 333 | 354 |  }
 | 
		
	
		
			
			| 334 | 355 |  
 | 
		
	
		
			
			| 335 | 356 |  /**
 | 
		
	
	
		
			
			|  | @@ -346,12 +367,14 @@ static void fbcon_handle_cup ( struct ansiesc_context *ctx,
 | 
		
	
		
			
			| 346 | 367 |  	int cx = ( params[1] - 1 );
 | 
		
	
		
			
			| 347 | 368 |  	int cy = ( params[0] - 1 );
 | 
		
	
		
			
			| 348 | 369 |  
 | 
		
	
		
			
			|  | 370 | +	fbcon_draw_cursor ( fbcon, 0 );
 | 
		
	
		
			
			| 349 | 371 |  	fbcon->xpos = cx;
 | 
		
	
		
			
			| 350 | 372 |  	if ( fbcon->xpos >= fbcon->character.width )
 | 
		
	
		
			
			| 351 | 373 |  		fbcon->xpos = ( fbcon->character.width - 1 );
 | 
		
	
		
			
			| 352 | 374 |  	fbcon->ypos = cy;
 | 
		
	
		
			
			| 353 | 375 |  	if ( fbcon->ypos >= fbcon->character.height )
 | 
		
	
		
			
			| 354 | 376 |  		fbcon->ypos = ( fbcon->character.height - 1 );
 | 
		
	
		
			
			|  | 377 | +	fbcon_draw_cursor ( fbcon, fbcon->show_cursor );
 | 
		
	
		
			
			| 355 | 378 |  }
 | 
		
	
		
			
			| 356 | 379 |  
 | 
		
	
		
			
			| 357 | 380 |  /**
 | 
		
	
	
		
			
			|  | @@ -375,6 +398,7 @@ static void fbcon_handle_ed ( struct ansiesc_context *ctx,
 | 
		
	
		
			
			| 375 | 398 |  	/* Reset cursor position */
 | 
		
	
		
			
			| 376 | 399 |  	fbcon->xpos = 0;
 | 
		
	
		
			
			| 377 | 400 |  	fbcon->ypos = 0;
 | 
		
	
		
			
			|  | 401 | +	fbcon_draw_cursor ( fbcon, fbcon->show_cursor );
 | 
		
	
		
			
			| 378 | 402 |  }
 | 
		
	
		
			
			| 379 | 403 |  
 | 
		
	
		
			
			| 380 | 404 |  /**
 | 
		
	
	
		
			
			|  | @@ -437,11 +461,45 @@ static void fbcon_handle_sgr ( struct ansiesc_context *ctx, unsigned int count,
 | 
		
	
		
			
			| 437 | 461 |  	}
 | 
		
	
		
			
			| 438 | 462 |  }
 | 
		
	
		
			
			| 439 | 463 |  
 | 
		
	
		
			
			|  | 464 | +/**
 | 
		
	
		
			
			|  | 465 | + * Handle ANSI DECTCEM set (show cursor)
 | 
		
	
		
			
			|  | 466 | + *
 | 
		
	
		
			
			|  | 467 | + * @v ctx		ANSI escape sequence context
 | 
		
	
		
			
			|  | 468 | + * @v count		Parameter count
 | 
		
	
		
			
			|  | 469 | + * @v params		List of graphic rendition aspects
 | 
		
	
		
			
			|  | 470 | + */
 | 
		
	
		
			
			|  | 471 | +static void fbcon_handle_dectcem_set ( struct ansiesc_context *ctx,
 | 
		
	
		
			
			|  | 472 | +				       unsigned int count __unused,
 | 
		
	
		
			
			|  | 473 | +				       int params[] __unused ) {
 | 
		
	
		
			
			|  | 474 | +	struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx );
 | 
		
	
		
			
			|  | 475 | +
 | 
		
	
		
			
			|  | 476 | +	fbcon->show_cursor = 1;
 | 
		
	
		
			
			|  | 477 | +	fbcon_draw_cursor ( fbcon, 1 );
 | 
		
	
		
			
			|  | 478 | +}
 | 
		
	
		
			
			|  | 479 | +
 | 
		
	
		
			
			|  | 480 | +/**
 | 
		
	
		
			
			|  | 481 | + * Handle ANSI DECTCEM reset (hide cursor)
 | 
		
	
		
			
			|  | 482 | + *
 | 
		
	
		
			
			|  | 483 | + * @v ctx		ANSI escape sequence context
 | 
		
	
		
			
			|  | 484 | + * @v count		Parameter count
 | 
		
	
		
			
			|  | 485 | + * @v params		List of graphic rendition aspects
 | 
		
	
		
			
			|  | 486 | + */
 | 
		
	
		
			
			|  | 487 | +static void fbcon_handle_dectcem_reset ( struct ansiesc_context *ctx,
 | 
		
	
		
			
			|  | 488 | +					 unsigned int count __unused,
 | 
		
	
		
			
			|  | 489 | +					 int params[] __unused ) {
 | 
		
	
		
			
			|  | 490 | +	struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx );
 | 
		
	
		
			
			|  | 491 | +
 | 
		
	
		
			
			|  | 492 | +	fbcon->show_cursor = 0;
 | 
		
	
		
			
			|  | 493 | +	fbcon_draw_cursor ( fbcon, 0 );
 | 
		
	
		
			
			|  | 494 | +}
 | 
		
	
		
			
			|  | 495 | +
 | 
		
	
		
			
			| 440 | 496 |  /** ANSI escape sequence handlers */
 | 
		
	
		
			
			| 441 | 497 |  static struct ansiesc_handler fbcon_ansiesc_handlers[] = {
 | 
		
	
		
			
			| 442 | 498 |  	{ ANSIESC_CUP, fbcon_handle_cup },
 | 
		
	
		
			
			| 443 | 499 |  	{ ANSIESC_ED, fbcon_handle_ed },
 | 
		
	
		
			
			| 444 | 500 |  	{ ANSIESC_SGR, fbcon_handle_sgr },
 | 
		
	
		
			
			|  | 501 | +	{ ANSIESC_DECTCEM_SET, fbcon_handle_dectcem_set },
 | 
		
	
		
			
			|  | 502 | +	{ ANSIESC_DECTCEM_RESET, fbcon_handle_dectcem_reset },
 | 
		
	
		
			
			| 445 | 503 |  	{ 0, NULL }
 | 
		
	
		
			
			| 446 | 504 |  };
 | 
		
	
		
			
			| 447 | 505 |  
 | 
		
	
	
		
			
			|  | @@ -462,35 +520,46 @@ void fbcon_putchar ( struct fbcon *fbcon, int character ) {
 | 
		
	
		
			
			| 462 | 520 |  	/* Handle control characters */
 | 
		
	
		
			
			| 463 | 521 |  	switch ( character ) {
 | 
		
	
		
			
			| 464 | 522 |  	case '\r':
 | 
		
	
		
			
			|  | 523 | +		fbcon_draw_cursor ( fbcon, 0 );
 | 
		
	
		
			
			| 465 | 524 |  		fbcon->xpos = 0;
 | 
		
	
		
			
			| 466 |  | -		return;
 | 
		
	
		
			
			|  | 525 | +		break;
 | 
		
	
		
			
			| 467 | 526 |  	case '\n':
 | 
		
	
		
			
			|  | 527 | +		fbcon_draw_cursor ( fbcon, 0 );
 | 
		
	
		
			
			| 468 | 528 |  		fbcon->xpos = 0;
 | 
		
	
		
			
			| 469 |  | -		fbcon_scroll ( fbcon );
 | 
		
	
		
			
			| 470 |  | -		return;
 | 
		
	
		
			
			|  | 529 | +		fbcon->ypos++;
 | 
		
	
		
			
			|  | 530 | +		break;
 | 
		
	
		
			
			| 471 | 531 |  	case '\b':
 | 
		
	
		
			
			|  | 532 | +		fbcon_draw_cursor ( fbcon, 0 );
 | 
		
	
		
			
			| 472 | 533 |  		if ( fbcon->xpos ) {
 | 
		
	
		
			
			| 473 | 534 |  			fbcon->xpos--;
 | 
		
	
		
			
			| 474 | 535 |  		} else if ( fbcon->ypos ) {
 | 
		
	
		
			
			| 475 | 536 |  			fbcon->xpos = ( fbcon->character.width - 1 );
 | 
		
	
		
			
			| 476 | 537 |  			fbcon->ypos--;
 | 
		
	
		
			
			| 477 | 538 |  		}
 | 
		
	
		
			
			| 478 |  | -		return;
 | 
		
	
		
			
			|  | 539 | +		break;
 | 
		
	
		
			
			|  | 540 | +	default:
 | 
		
	
		
			
			|  | 541 | +		/* Print character at current cursor position */
 | 
		
	
		
			
			|  | 542 | +		cell.foreground = ( fbcon->foreground | fbcon->bold );
 | 
		
	
		
			
			|  | 543 | +		cell.background = fbcon->background;
 | 
		
	
		
			
			|  | 544 | +		cell.character = character;
 | 
		
	
		
			
			|  | 545 | +		fbcon_store_character ( fbcon, &cell, fbcon->xpos, fbcon->ypos);
 | 
		
	
		
			
			|  | 546 | +		fbcon_draw_character ( fbcon, &cell, fbcon->xpos, fbcon->ypos );
 | 
		
	
		
			
			|  | 547 | +
 | 
		
	
		
			
			|  | 548 | +		/* Advance cursor */
 | 
		
	
		
			
			|  | 549 | +		fbcon->xpos++;
 | 
		
	
		
			
			|  | 550 | +		if ( fbcon->xpos >= fbcon->character.width ) {
 | 
		
	
		
			
			|  | 551 | +			fbcon->xpos = 0;
 | 
		
	
		
			
			|  | 552 | +			fbcon->ypos++;
 | 
		
	
		
			
			|  | 553 | +		}
 | 
		
	
		
			
			|  | 554 | +		break;
 | 
		
	
		
			
			| 479 | 555 |  	}
 | 
		
	
		
			
			| 480 | 556 |  
 | 
		
	
		
			
			| 481 |  | -	/* Print character at current cursor position */
 | 
		
	
		
			
			| 482 |  | -	cell.foreground = ( fbcon->foreground | fbcon->bold );
 | 
		
	
		
			
			| 483 |  | -	cell.background = fbcon->background;
 | 
		
	
		
			
			| 484 |  | -	cell.character = character;
 | 
		
	
		
			
			| 485 |  | -	fbcon_store_character ( fbcon, &cell, fbcon->xpos, fbcon->ypos );
 | 
		
	
		
			
			| 486 |  | -	fbcon_draw_character ( fbcon, &cell, fbcon->xpos, fbcon->ypos );
 | 
		
	
		
			
			| 487 |  | -
 | 
		
	
		
			
			| 488 |  | -	/* Advance cursor */
 | 
		
	
		
			
			| 489 |  | -	fbcon->xpos++;
 | 
		
	
		
			
			| 490 |  | -	if ( fbcon->xpos >= fbcon->character.width ) {
 | 
		
	
		
			
			| 491 |  | -		fbcon->xpos = 0;
 | 
		
	
		
			
			|  | 557 | +	/* Scroll screen if necessary */
 | 
		
	
		
			
			|  | 558 | +	if ( fbcon->ypos >= fbcon->character.height )
 | 
		
	
		
			
			| 492 | 559 |  		fbcon_scroll ( fbcon );
 | 
		
	
		
			
			| 493 |  | -	}
 | 
		
	
		
			
			|  | 560 | +
 | 
		
	
		
			
			|  | 561 | +	/* Show cursor */
 | 
		
	
		
			
			|  | 562 | +	fbcon_draw_cursor ( fbcon, fbcon->show_cursor );
 | 
		
	
		
			
			| 494 | 563 |  }
 | 
		
	
		
			
			| 495 | 564 |  
 | 
		
	
		
			
			| 496 | 565 |  /**
 | 
		
	
	
		
			
			|  | @@ -673,6 +742,7 @@ int fbcon_init ( struct fbcon *fbcon, userptr_t start,
 | 
		
	
		
			
			| 673 | 742 |  	fbcon->map = map;
 | 
		
	
		
			
			| 674 | 743 |  	fbcon->font = font;
 | 
		
	
		
			
			| 675 | 744 |  	fbcon->ctx.handlers = fbcon_ansiesc_handlers;
 | 
		
	
		
			
			|  | 745 | +	fbcon->show_cursor = 1;
 | 
		
	
		
			
			| 676 | 746 |  
 | 
		
	
		
			
			| 677 | 747 |  	/* Derive overall length */
 | 
		
	
		
			
			| 678 | 748 |  	fbcon->len = ( pixel->height * pixel->stride );
 |