From patchwork Sat Oct 13 19:31:59 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 191306 X-Patchwork-Delegate: agust@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 892822C008F for ; Sun, 14 Oct 2012 06:33:13 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 1E08D4A02D; Sat, 13 Oct 2012 21:33:12 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id WKjRX66WVSao; Sat, 13 Oct 2012 21:33:11 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 56EC14A01E; Sat, 13 Oct 2012 21:33:10 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id A9E9D4A01C for ; Sat, 13 Oct 2012 21:33:07 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id EpWZ7DB8cs6X for ; Sat, 13 Oct 2012 21:33:06 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-we0-f172.google.com (mail-we0-f172.google.com [74.125.82.172]) by theia.denx.de (Postfix) with ESMTPS id B37434A029 for ; Sat, 13 Oct 2012 21:33:01 +0200 (CEST) Received: by mail-we0-f172.google.com with SMTP id u46so2366333wey.3 for ; Sat, 13 Oct 2012 12:33:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=kX4upBfA0ug03VUbkjdjoVy2GitDAgpyxYpN1vDYBoA=; b=JH/BCYM2Gn4ybeCvrELzSbgndn1slBtv410d38nY9X9S60xU+GsAtBVAJ/Tv22zbF8 sfFjj7Pm0keLYYPS8EpIuTtRqyc7IrREXe3VeQhoYu5w/ivRKZz+5UhUoz/KUWGYxUPw 5YhP9nzSeb6t+y48I4KIt+URqJyMCP4NpHOdY03+HTpRpHNBN5+rFt3Prav4DsA4lJxX oehozlEaOBEwG9OIsHH1h3ftUM3Lgren/RHfwoDRbHsfgDUKE+TYZ0xzMEUWO6Kf3THn r8TJvFZnQszdw4aLst82o1QZnJ6fMIC9XKkusB1/NnVk7M4dwmESSMprsXkjQBgGGQBm NihQ== Received: by 10.180.80.33 with SMTP id o1mr13644029wix.14.1350156781241; Sat, 13 Oct 2012 12:33:01 -0700 (PDT) Received: from Pali-EliteBook.kolej.mff.cuni.cz (pali.kolej.mff.cuni.cz. [78.128.193.202]) by mx.google.com with ESMTPS id ei1sm5293959wid.7.2012.10.13.12.32.59 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 13 Oct 2012 12:33:00 -0700 (PDT) From: =?UTF-8?q?Pali=20Roh=C3=A1r?= To: u-boot@lists.denx.de Date: Sat, 13 Oct 2012 21:31:59 +0200 Message-Id: <1350156720-13387-5-git-send-email-pali.rohar@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1350156720-13387-1-git-send-email-pali.rohar@gmail.com> References: <1327415291-13260-1-git-send-email-pali.rohar@gmail.com> <1350156720-13387-1-git-send-email-pali.rohar@gmail.com> MIME-Version: 1.0 Cc: =?UTF-8?q?Pali=20Roh=C3=A1r?= Subject: [U-Boot] [PATCH v3 4/5] cfb_console: Add support for some ANSI terminal escape codes X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de * This patch add support for move cursor, reverse colors and clear console via ANSI espace codes in cfb_console driver * ANSI escape codes can be enabled/disabled via CONFIG_CFB_CONSOLE_ANSI Signed-off-by: Pali Rohár --- Changes since v2: - Fixed multiline comments Changes since v1: - Added support ANSI code show/hide cursor - Added info to README Changes since original version: - Fixed commit message README | 3 + drivers/video/cfb_console.c | 313 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 307 insertions(+), 9 deletions(-) diff --git a/README b/README index 9804cea..d45a91d 100644 --- a/README +++ b/README @@ -655,6 +655,9 @@ The following options need to be configured: additional board info beside the logo + When CONFIG_CFB_CONSOLE_ANSI is defined, console will have + ANSI terminal support. Needed for CONFIG_CMDLINE_EDITING. + When CONFIG_CFB_CONSOLE is defined, video console is default i/o. Serial console can be forced with environment 'console=serial'. diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index 9f7794f..3ed96d3 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -385,6 +385,11 @@ static u32 eorx, fgx, bgx; /* color pats */ static int cfb_do_flush_cache; +static char ansi_buf[10] = { 0, }; +static int ansi_buf_size; +static int ansi_colors_need_revert; +static int ansi_cursor_hidden; + static const int video_font_draw_table8[] = { 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, @@ -612,6 +617,14 @@ static void video_putchar(int xx, int yy, unsigned char c) video_drawchars(xx, yy + video_logo_height, &c, 1); } +static void console_swap_colors(void) +{ + eorx = fgx; + fgx = bgx; + bgx = eorx; + eorx = fgx ^ bgx; +} + #if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR) static void video_set_cursor(void) { @@ -695,6 +708,21 @@ static void memcpyl(int *d, int *s, int c) } #endif +static void console_clear(void) +{ +#ifdef VIDEO_HW_RECTFILL + video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */ + 0, /* dest pos x */ + video_logo_height, /* dest pos y */ + VIDEO_VISIBLE_COLS, /* frame width */ + VIDEO_VISIBLE_ROWS, /* frame height */ + bgx /* fill color */ + ); +#else + memsetl(CONSOLE_ROW_FIRST, CONSOLE_SIZE, bgx); +#endif +} + static void console_clear_line(int line, int begin, int end) { #ifdef VIDEO_HW_RECTFILL @@ -768,9 +796,54 @@ static void console_back(void) } } -static void console_newline(void) +static void console_cursor_fix(void) +{ + if (console_row < 0) + console_row = 0; + if (console_row >= CONSOLE_ROWS) + console_row = CONSOLE_ROWS-1; + if (console_col < 0) + console_col = 0; + if (console_col >= CONSOLE_COLS) + console_col = CONSOLE_COLS-1; +} + +static void console_cursor_up(int n) +{ + console_row -= n; + console_cursor_fix(); +} + +static void console_cursor_down(int n) +{ + console_row += n; + console_cursor_fix(); +} + +static void console_cursor_left(int n) +{ + console_col -= n; + console_cursor_fix(); +} + +static void console_cursor_right(int n) +{ + console_col += n; + console_cursor_fix(); +} + +static void console_cursor_set_position(int row, int col) +{ + if (console_row != -1) + console_row = row; + if (console_col != -1) + console_col = col; + console_cursor_fix(); +} + +static void console_newline(int n) { - console_row++; + console_row += n; console_col = 0; /* Check if we need to scroll the terminal */ @@ -779,20 +852,28 @@ static void console_newline(void) console_scrollup(); /* Decrement row number */ - console_row--; + console_row = CONSOLE_ROWS-1; } } +static void console_previewsline(int n) +{ + /* FIXME: also scroll terminal ? */ + console_row -= n; + console_cursor_fix(); +} + static void console_cr(void) { console_col = 0; } -void video_putc(const char c) +static void parse_putc(const char c) { static int nl = 1; - CURSOR_OFF; + if (!ansi_cursor_hidden) + CURSOR_OFF; switch (c) { case 13: /* back to first column */ @@ -801,7 +882,7 @@ void video_putc(const char c) case '\n': /* next line */ if (console_col || (!console_col && nl)) - console_newline(); + console_newline(1); nl = 1; break; @@ -810,7 +891,7 @@ void video_putc(const char c) console_col &= ~0x0007; if (console_col >= CONSOLE_COLS) - console_newline(); + console_newline(1); break; case 8: /* backspace */ @@ -827,11 +908,225 @@ void video_putc(const char c) /* check for newline */ if (console_col >= CONSOLE_COLS) { - console_newline(); + console_newline(1); nl = 0; } } - CURSOR_SET; + + if (!ansi_cursor_hidden) + CURSOR_SET; +} + +void video_putc(const char c) +{ +#ifdef CONFIG_CFB_CONSOLE_ANSI + int i; + + if (c == 27) { + for (i = 0; i < ansi_buf_size; ++i) + parse_putc(ansi_buf[i]); + ansi_buf[0] = 27; + ansi_buf_size = 1; + return; + } + + if (ansi_buf_size > 0) { + /* + * 0 - ESC + * 1 - [ + * 2 - num1 + * 3 - .. + * 4 - ; + * 5 - num2 + * 6 - .. + * - cchar + */ + int next = 0; + + int flush = 0; + int fail = 0; + + int num1 = 0; + int num2 = 0; + int cchar = 0; + + ansi_buf[ansi_buf_size++] = c; + + if (ansi_buf_size >= sizeof(ansi_buf)) + fail = 1; + + for (i = 0; i < ansi_buf_size; ++i) { + if (fail) + break; + + switch (next) { + case 0: + if (ansi_buf[i] == 27) + next = 1; + else + fail = 1; + break; + + case 1: + if (ansi_buf[i] == '[') + next = 2; + else + fail = 1; + break; + + case 2: + if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { + num1 = ansi_buf[i]-'0'; + next = 3; + } else if (ansi_buf[i] != '?') { + --i; + num1 = 1; + next = 4; + } + break; + + case 3: + if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { + num1 *= 10; + num1 += ansi_buf[i]-'0'; + } else { + --i; + next = 4; + } + break; + + case 4: + if (ansi_buf[i] != ';') { + --i; + next = 7; + } else + next = 5; + break; + + case 5: + if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { + num2 = ansi_buf[i]-'0'; + next = 6; + } else + fail = 1; + break; + + case 6: + if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { + num2 *= 10; + num2 += ansi_buf[i]-'0'; + } else { + --i; + next = 7; + } + break; + + case 7: + if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H') + || ansi_buf[i] == 'J' + || ansi_buf[i] == 'K' + || ansi_buf[i] == 'h' + || ansi_buf[i] == 'l' + || ansi_buf[i] == 'm') { + cchar = ansi_buf[i]; + flush = 1; + } else + fail = 1; + break; + } + } + + if (fail) { + for (i = 0; i < ansi_buf_size; ++i) + parse_putc(ansi_buf[i]); + ansi_buf_size = 0; + return; + } + + if (flush) { + if (!ansi_cursor_hidden) + CURSOR_OFF; + ansi_buf_size = 0; + switch (cchar) { + case 'A': + /* move cursor num1 rows up */ + console_cursor_up(num1); + break; + case 'B': + /* move cursor num1 rows down */ + console_cursor_down(num1); + break; + case 'C': + /* move cursor num1 columns forward */ + console_cursor_right(num1); + break; + case 'D': + /* move cursor num1 columns back */ + console_cursor_left(num1); + break; + case 'E': + /* move cursor num1 rows up at begin of row */ + console_previewsline(num1); + break; + case 'F': + /* move cursor num1 rows down at begin of row */ + console_newline(num1); + break; + case 'G': + /* move cursor to column num1 */ + console_cursor_set_position(-1, num1-1); + break; + case 'H': + /* move cursor to row num1, column num2 */ + console_cursor_set_position(num1-1, num2-1); + break; + case 'J': + /* clear console and move cursor to 0, 0 */ + console_clear(); + console_cursor_set_position(0, 0); + break; + case 'K': + /* clear line */ + if (num1 == 0) + console_clear_line(console_row, + console_col, + CONSOLE_COLS-1); + else if (num1 == 1) + console_clear_line(console_row, + 0, console_col); + else + console_clear_line(console_row, + 0, CONSOLE_COLS-1); + break; + case 'h': + ansi_cursor_hidden = 0; + break; + case 'l': + ansi_cursor_hidden = 1; + break; + case 'm': + if (num1 == 0) { /* reset swapped colors */ + if (ansi_colors_need_revert) { + console_swap_colors(); + ansi_colors_need_revert = 0; + } + } else if (num1 == 7) { /* once swap colors */ + if (!ansi_colors_need_revert) { + console_swap_colors(); + ansi_colors_need_revert = 1; + } + } + break; + } + if (!ansi_cursor_hidden) + CURSOR_SET; + } + } else { + parse_putc(c); + } +#else + parse_putc(c); +#endif } void video_puts(const char *s)