Commit 33a35bbbe09a9b63b46e86a97d5dfbdae5481401
Committed by
Tom Rini
1 parent
318e70e244
Exists in
master
and in
54 other branches
cfb_console: Add support for some ANSI terminal escape codes
Add optional support for some ANSI escape sequences to the cfb_console driver. Define CONFIG_CFB_CONSOLE_ANSI to enable cursor moving, color reverting and clearing the cfb console via ANSI escape codes. Signed-off-by: Pali Rohár <pali.rohar@gmail.com> Signed-off-by: Anatolij Gustschin <agust@denx.de>
Showing 2 changed files with 323 additions and 9 deletions Side-by-side Diff
README
... | ... | @@ -655,6 +655,10 @@ |
655 | 655 | additional board info beside |
656 | 656 | the logo |
657 | 657 | |
658 | + When CONFIG_CFB_CONSOLE_ANSI is defined, console will support | |
659 | + a limited number of ANSI escape sequences (cursor control, | |
660 | + erase functions and limited graphics rendition control). | |
661 | + | |
658 | 662 | When CONFIG_CFB_CONSOLE is defined, video console is |
659 | 663 | default i/o. Serial console can be forced with |
660 | 664 | environment 'console=serial'. |
drivers/video/cfb_console.c
... | ... | @@ -385,6 +385,13 @@ |
385 | 385 | |
386 | 386 | static int cfb_do_flush_cache; |
387 | 387 | |
388 | +#ifdef CONFIG_CFB_CONSOLE_ANSI | |
389 | +static char ansi_buf[10]; | |
390 | +static int ansi_buf_size; | |
391 | +static int ansi_colors_need_revert; | |
392 | +static int ansi_cursor_hidden; | |
393 | +#endif | |
394 | + | |
388 | 395 | static const int video_font_draw_table8[] = { |
389 | 396 | 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, |
390 | 397 | 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, |
391 | 398 | |
... | ... | @@ -768,9 +775,97 @@ |
768 | 775 | } |
769 | 776 | } |
770 | 777 | |
771 | -static void console_newline(void) | |
778 | +#ifdef CONFIG_CFB_CONSOLE_ANSI | |
779 | + | |
780 | +static void console_clear(void) | |
772 | 781 | { |
773 | - console_row++; | |
782 | +#ifdef VIDEO_HW_RECTFILL | |
783 | + video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */ | |
784 | + 0, /* dest pos x */ | |
785 | + video_logo_height, /* dest pos y */ | |
786 | + VIDEO_VISIBLE_COLS, /* frame width */ | |
787 | + VIDEO_VISIBLE_ROWS, /* frame height */ | |
788 | + bgx /* fill color */ | |
789 | + ); | |
790 | +#else | |
791 | + memsetl(CONSOLE_ROW_FIRST, CONSOLE_SIZE, bgx); | |
792 | +#endif | |
793 | +} | |
794 | + | |
795 | +static void console_cursor_fix(void) | |
796 | +{ | |
797 | + if (console_row < 0) | |
798 | + console_row = 0; | |
799 | + if (console_row >= CONSOLE_ROWS) | |
800 | + console_row = CONSOLE_ROWS - 1; | |
801 | + if (console_col < 0) | |
802 | + console_col = 0; | |
803 | + if (console_col >= CONSOLE_COLS) | |
804 | + console_col = CONSOLE_COLS - 1; | |
805 | +} | |
806 | + | |
807 | +static void console_cursor_up(int n) | |
808 | +{ | |
809 | + console_row -= n; | |
810 | + console_cursor_fix(); | |
811 | +} | |
812 | + | |
813 | +static void console_cursor_down(int n) | |
814 | +{ | |
815 | + console_row += n; | |
816 | + console_cursor_fix(); | |
817 | +} | |
818 | + | |
819 | +static void console_cursor_left(int n) | |
820 | +{ | |
821 | + console_col -= n; | |
822 | + console_cursor_fix(); | |
823 | +} | |
824 | + | |
825 | +static void console_cursor_right(int n) | |
826 | +{ | |
827 | + console_col += n; | |
828 | + console_cursor_fix(); | |
829 | +} | |
830 | + | |
831 | +static void console_cursor_set_position(int row, int col) | |
832 | +{ | |
833 | + if (console_row != -1) | |
834 | + console_row = row; | |
835 | + if (console_col != -1) | |
836 | + console_col = col; | |
837 | + console_cursor_fix(); | |
838 | +} | |
839 | + | |
840 | +static void console_previousline(int n) | |
841 | +{ | |
842 | + /* FIXME: also scroll terminal ? */ | |
843 | + console_row -= n; | |
844 | + console_cursor_fix(); | |
845 | +} | |
846 | + | |
847 | +static void console_swap_colors(void) | |
848 | +{ | |
849 | + eorx = fgx; | |
850 | + fgx = bgx; | |
851 | + bgx = eorx; | |
852 | + eorx = fgx ^ bgx; | |
853 | +} | |
854 | + | |
855 | +static inline int console_cursor_is_visible(void) | |
856 | +{ | |
857 | + return !ansi_cursor_hidden; | |
858 | +} | |
859 | +#else | |
860 | +static inline int console_cursor_is_visible(void) | |
861 | +{ | |
862 | + return 1; | |
863 | +} | |
864 | +#endif | |
865 | + | |
866 | +static void console_newline(int n) | |
867 | +{ | |
868 | + console_row += n; | |
774 | 869 | console_col = 0; |
775 | 870 | |
776 | 871 | /* Check if we need to scroll the terminal */ |
... | ... | @@ -779,7 +874,7 @@ |
779 | 874 | console_scrollup(); |
780 | 875 | |
781 | 876 | /* Decrement row number */ |
782 | - console_row--; | |
877 | + console_row = CONSOLE_ROWS - 1; | |
783 | 878 | } |
784 | 879 | } |
785 | 880 | |
786 | 881 | |
... | ... | @@ -788,11 +883,12 @@ |
788 | 883 | console_col = 0; |
789 | 884 | } |
790 | 885 | |
791 | -void video_putc(const char c) | |
886 | +static void parse_putc(const char c) | |
792 | 887 | { |
793 | 888 | static int nl = 1; |
794 | 889 | |
795 | - CURSOR_OFF; | |
890 | + if (console_cursor_is_visible()) | |
891 | + CURSOR_OFF; | |
796 | 892 | |
797 | 893 | switch (c) { |
798 | 894 | case 13: /* back to first column */ |
... | ... | @@ -801,7 +897,7 @@ |
801 | 897 | |
802 | 898 | case '\n': /* next line */ |
803 | 899 | if (console_col || (!console_col && nl)) |
804 | - console_newline(); | |
900 | + console_newline(1); | |
805 | 901 | nl = 1; |
806 | 902 | break; |
807 | 903 | |
... | ... | @@ -810,7 +906,7 @@ |
810 | 906 | console_col &= ~0x0007; |
811 | 907 | |
812 | 908 | if (console_col >= CONSOLE_COLS) |
813 | - console_newline(); | |
909 | + console_newline(1); | |
814 | 910 | break; |
815 | 911 | |
816 | 912 | case 8: /* backspace */ |
817 | 913 | |
... | ... | @@ -827,11 +923,225 @@ |
827 | 923 | |
828 | 924 | /* check for newline */ |
829 | 925 | if (console_col >= CONSOLE_COLS) { |
830 | - console_newline(); | |
926 | + console_newline(1); | |
831 | 927 | nl = 0; |
832 | 928 | } |
833 | 929 | } |
834 | - CURSOR_SET; | |
930 | + | |
931 | + if (console_cursor_is_visible()) | |
932 | + CURSOR_SET; | |
933 | +} | |
934 | + | |
935 | +void video_putc(const char c) | |
936 | +{ | |
937 | +#ifdef CONFIG_CFB_CONSOLE_ANSI | |
938 | + int i; | |
939 | + | |
940 | + if (c == 27) { | |
941 | + for (i = 0; i < ansi_buf_size; ++i) | |
942 | + parse_putc(ansi_buf[i]); | |
943 | + ansi_buf[0] = 27; | |
944 | + ansi_buf_size = 1; | |
945 | + return; | |
946 | + } | |
947 | + | |
948 | + if (ansi_buf_size > 0) { | |
949 | + /* | |
950 | + * 0 - ESC | |
951 | + * 1 - [ | |
952 | + * 2 - num1 | |
953 | + * 3 - .. | |
954 | + * 4 - ; | |
955 | + * 5 - num2 | |
956 | + * 6 - .. | |
957 | + * - cchar | |
958 | + */ | |
959 | + int next = 0; | |
960 | + | |
961 | + int flush = 0; | |
962 | + int fail = 0; | |
963 | + | |
964 | + int num1 = 0; | |
965 | + int num2 = 0; | |
966 | + int cchar = 0; | |
967 | + | |
968 | + ansi_buf[ansi_buf_size++] = c; | |
969 | + | |
970 | + if (ansi_buf_size >= sizeof(ansi_buf)) | |
971 | + fail = 1; | |
972 | + | |
973 | + for (i = 0; i < ansi_buf_size; ++i) { | |
974 | + if (fail) | |
975 | + break; | |
976 | + | |
977 | + switch (next) { | |
978 | + case 0: | |
979 | + if (ansi_buf[i] == 27) | |
980 | + next = 1; | |
981 | + else | |
982 | + fail = 1; | |
983 | + break; | |
984 | + | |
985 | + case 1: | |
986 | + if (ansi_buf[i] == '[') | |
987 | + next = 2; | |
988 | + else | |
989 | + fail = 1; | |
990 | + break; | |
991 | + | |
992 | + case 2: | |
993 | + if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { | |
994 | + num1 = ansi_buf[i]-'0'; | |
995 | + next = 3; | |
996 | + } else if (ansi_buf[i] != '?') { | |
997 | + --i; | |
998 | + num1 = 1; | |
999 | + next = 4; | |
1000 | + } | |
1001 | + break; | |
1002 | + | |
1003 | + case 3: | |
1004 | + if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { | |
1005 | + num1 *= 10; | |
1006 | + num1 += ansi_buf[i]-'0'; | |
1007 | + } else { | |
1008 | + --i; | |
1009 | + next = 4; | |
1010 | + } | |
1011 | + break; | |
1012 | + | |
1013 | + case 4: | |
1014 | + if (ansi_buf[i] != ';') { | |
1015 | + --i; | |
1016 | + next = 7; | |
1017 | + } else | |
1018 | + next = 5; | |
1019 | + break; | |
1020 | + | |
1021 | + case 5: | |
1022 | + if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { | |
1023 | + num2 = ansi_buf[i]-'0'; | |
1024 | + next = 6; | |
1025 | + } else | |
1026 | + fail = 1; | |
1027 | + break; | |
1028 | + | |
1029 | + case 6: | |
1030 | + if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') { | |
1031 | + num2 *= 10; | |
1032 | + num2 += ansi_buf[i]-'0'; | |
1033 | + } else { | |
1034 | + --i; | |
1035 | + next = 7; | |
1036 | + } | |
1037 | + break; | |
1038 | + | |
1039 | + case 7: | |
1040 | + if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H') | |
1041 | + || ansi_buf[i] == 'J' | |
1042 | + || ansi_buf[i] == 'K' | |
1043 | + || ansi_buf[i] == 'h' | |
1044 | + || ansi_buf[i] == 'l' | |
1045 | + || ansi_buf[i] == 'm') { | |
1046 | + cchar = ansi_buf[i]; | |
1047 | + flush = 1; | |
1048 | + } else | |
1049 | + fail = 1; | |
1050 | + break; | |
1051 | + } | |
1052 | + } | |
1053 | + | |
1054 | + if (fail) { | |
1055 | + for (i = 0; i < ansi_buf_size; ++i) | |
1056 | + parse_putc(ansi_buf[i]); | |
1057 | + ansi_buf_size = 0; | |
1058 | + return; | |
1059 | + } | |
1060 | + | |
1061 | + if (flush) { | |
1062 | + if (!ansi_cursor_hidden) | |
1063 | + CURSOR_OFF; | |
1064 | + ansi_buf_size = 0; | |
1065 | + switch (cchar) { | |
1066 | + case 'A': | |
1067 | + /* move cursor num1 rows up */ | |
1068 | + console_cursor_up(num1); | |
1069 | + break; | |
1070 | + case 'B': | |
1071 | + /* move cursor num1 rows down */ | |
1072 | + console_cursor_down(num1); | |
1073 | + break; | |
1074 | + case 'C': | |
1075 | + /* move cursor num1 columns forward */ | |
1076 | + console_cursor_right(num1); | |
1077 | + break; | |
1078 | + case 'D': | |
1079 | + /* move cursor num1 columns back */ | |
1080 | + console_cursor_left(num1); | |
1081 | + break; | |
1082 | + case 'E': | |
1083 | + /* move cursor num1 rows up at begin of row */ | |
1084 | + console_previousline(num1); | |
1085 | + break; | |
1086 | + case 'F': | |
1087 | + /* move cursor num1 rows down at begin of row */ | |
1088 | + console_newline(num1); | |
1089 | + break; | |
1090 | + case 'G': | |
1091 | + /* move cursor to column num1 */ | |
1092 | + console_cursor_set_position(-1, num1-1); | |
1093 | + break; | |
1094 | + case 'H': | |
1095 | + /* move cursor to row num1, column num2 */ | |
1096 | + console_cursor_set_position(num1-1, num2-1); | |
1097 | + break; | |
1098 | + case 'J': | |
1099 | + /* clear console and move cursor to 0, 0 */ | |
1100 | + console_clear(); | |
1101 | + console_cursor_set_position(0, 0); | |
1102 | + break; | |
1103 | + case 'K': | |
1104 | + /* clear line */ | |
1105 | + if (num1 == 0) | |
1106 | + console_clear_line(console_row, | |
1107 | + console_col, | |
1108 | + CONSOLE_COLS-1); | |
1109 | + else if (num1 == 1) | |
1110 | + console_clear_line(console_row, | |
1111 | + 0, console_col); | |
1112 | + else | |
1113 | + console_clear_line(console_row, | |
1114 | + 0, CONSOLE_COLS-1); | |
1115 | + break; | |
1116 | + case 'h': | |
1117 | + ansi_cursor_hidden = 0; | |
1118 | + break; | |
1119 | + case 'l': | |
1120 | + ansi_cursor_hidden = 1; | |
1121 | + break; | |
1122 | + case 'm': | |
1123 | + if (num1 == 0) { /* reset swapped colors */ | |
1124 | + if (ansi_colors_need_revert) { | |
1125 | + console_swap_colors(); | |
1126 | + ansi_colors_need_revert = 0; | |
1127 | + } | |
1128 | + } else if (num1 == 7) { /* once swap colors */ | |
1129 | + if (!ansi_colors_need_revert) { | |
1130 | + console_swap_colors(); | |
1131 | + ansi_colors_need_revert = 1; | |
1132 | + } | |
1133 | + } | |
1134 | + break; | |
1135 | + } | |
1136 | + if (!ansi_cursor_hidden) | |
1137 | + CURSOR_SET; | |
1138 | + } | |
1139 | + } else { | |
1140 | + parse_putc(c); | |
1141 | + } | |
1142 | +#else | |
1143 | + parse_putc(c); | |
1144 | +#endif | |
835 | 1145 | } |
836 | 1146 | |
837 | 1147 | void video_puts(const char *s) |