console: Added escape sequences for screen
[meinos.git] / apps / console / screen.c
blobc3c0f97f5eba410141f0b5347ba755b842bbc36f
1 /*
2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <devfs.h>
22 #include <string.h>
23 #include <misc.h>
24 #include <unistd.h>
25 #include <ioport.h>
26 #include <ctype.h>
28 #include "console.h"
30 #define VIDEOTEXT_WIDTH 80 // 80 Cols (chars per line)
31 #define VIDEOTEXT_HEIGHT 25 // 25 Rows (lines)
32 #define VIDEOTEXT_SIZE 4000 // Video size
33 #define VIDEOTEXT_STDCOLOR 0x07 // Default color: black background, lightgray foreground
34 #define VIDEOTEXT_STDCOL 0 // Default col
35 #define VIDEOTEXT_STDROW 0 // Default row
37 #define SCREEN_DEFAULT_FONT "standard"
39 #define cursor_offset() (cursor.row*VIDEOTEXT_WIDTH+cursor.col)
41 // see http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c
42 // for changing fonts
44 static struct {
45 int col;
46 int row;
47 } cursor,saved_cursor;
49 static struct {
50 int linewrap;
51 int bell_freq;
52 int bell_dur;
53 int color;
54 } settings;
56 static uint16_t *videomem;
58 /**
59 * Rings the bell
60 * @param freq Frequency
61 * @param dur Duration time
63 static void bell(int freq,int dur) {
64 freq = 1193180/freq;
65 outb(0x43,0xB6);
66 outb(0x42,(uint8_t)freq);
67 outb(0x42,(uint8_t)(freq>>8));
68 outb(0x61,inb(0x61)|3);
69 sleep(dur);
70 outb(0x61,inb(0x61)&~3);
73 /**
74 * Clears screen
76 static void clearscreen() {
77 memset(videomem,0,VIDEOTEXT_SIZE);
78 cursor.col = VIDEOTEXT_STDCOL;
79 cursor.row = VIDEOTEXT_STDROW;
82 /**
83 * Sets default settings
85 static void default_settings() {
86 settings.linewrap = 1;
87 settings.bell_freq = 440;
88 settings.bell_dur = 100;
89 settings.color = VIDEOTEXT_STDCOLOR;
92 /**
93 * Prints a character on screen
94 * @param chr Character
96 static int printchar(char chr) {
97 size_t pos = cursor_offset();
98 static int escape = 0;
99 static char escape_buf[32];
101 if (escape) {
102 escape_buf[(escape++)-1] = chr; // put byte in escape buffer
104 if (isalpha(chr)) { // escape code finished
105 escape = 0;
106 if (escape==1 && escape_buf[0]=='c') default_settings(); // reset device
107 else if (escape==3 && memcmp(escape_buf,"[7h",3)==0) settings.linewrap = 1; // enable linewrap
108 else if (escape==3 && memcmp(escape_buf,"[7l",3)==0) settings.linewrap = 0; // disable linewrap
109 else if (escape_buf[0]=='[' && (escape_buf[escape-2]=='H' || escape_buf[escape-2]=='f')) { // set cursor position
110 int row = -1;
111 int col = -1;
112 if (escape>3) sscanf(escape_buf,escape_buf[escape-2]=='H'?"[%d;%dH":"[%d;%df",&row,&col);
113 if (row!=-1 && col!=-1) {
114 cursor.col = col;
115 cursor.row = row;
117 else {
118 cursor.col = 0;
119 cursor.row = 0;
122 else if (escape_buf[0]=='[' && escape_buf[escape-2]=='A') {
123 int up = 1;
124 if (escape>3) sscanf(escape_buf,"[%dA",&up);
125 if (cursor.row>0) cursor.row -= up;
127 else if (escape_buf[0]=='[' && escape_buf[escape-2]=='B') {
128 int down = 1;
129 if (escape>3) sscanf(escape_buf,"[%dB",&down);
130 if (cursor.row<VIDEOTEXT_HEIGHT) cursor.row += down;
132 else if (escape_buf[0]=='[' && escape_buf[escape-2]=='C') {
133 int left = 1;
134 if (escape>3) sscanf(escape_buf,"[%dC",&left);
135 if (cursor.col>0) cursor.col -= left;
137 else if (escape_buf[0]=='[' && escape_buf[escape-2]=='D') {
138 int right = 1;
139 if (escape>3) sscanf(escape_buf,"[%dD",&right);
140 if (cursor.col<VIDEOTEXT_WIDTH) cursor.col += right;
142 else if (escape_buf[0]=='[' && (escape_buf[1]=='s' || escape_buf[1]=='7')) {
143 memcpy(&saved_cursor,&cursor,sizeof(cursor));
145 else if (escape_buf[0]=='[' && (escape_buf[1]=='u' || escape_buf[1]=='8')) {
146 memcpy(&cursor,&saved_cursor,sizeof(cursor));
148 else if (memcmp(escape_buf,"[K",2)==0) {
149 memset(videomem+pos,0,(VIDEOTEXT_WIDTH-cursor.col+1)*2);
151 else if (memcmp(escape_buf,"[1K",3)==0) {
152 memset(videomem+VIDEOTEXT_WIDTH*cursor.col,0,cursor.row*2);
154 else if (memcmp(escape_buf,"[2K",3)==0) {
155 memset(videomem+VIDEOTEXT_WIDTH*cursor.col,0,VIDEOTEXT_WIDTH);
157 else if (memcmp(escape_buf,"[J",2)==0) {
158 memset(videomem+VIDEOTEXT_WIDTH*cursor.col,0,(VIDEOTEXT_HEIGHT-cursor.row)*VIDEOTEXT_WIDTH*2);
160 else if (memcmp(escape_buf,"[1J",3)==0) {
161 memset(videomem,0,cursor.row*VIDEOTEXT_WIDTH*2);
163 else if (memcmp(escape_buf,"[2J",3)==0) {
164 clearscreen();
168 else if (chr=='\a') bell(settings.bell_freq,settings.bell_dur);
169 else if (chr=='\b') cursor.col = (cursor.col-1>0)?(cursor.col-1):0;
170 else if (chr=='\t') cursor.col = cursor.col+5;
171 else if (chr=='\n') {
172 cursor.row++;
173 cursor.col = VIDEOTEXT_STDCOL;
175 else if (chr=='\f') clearscreen();
176 else if (chr=='\r') cursor.col = VIDEOTEXT_STDCOL;
177 else if (chr==0x1B) escape = 1;
178 else if (chr>=' ') {
179 *(videomem+pos) = (((uint16_t)settings.color)<<8)|chr;
180 cursor.col++;
183 if (cursor.col>=VIDEOTEXT_WIDTH) {
184 cursor.col = cursor.col-VIDEOTEXT_WIDTH;
185 cursor.row++;
187 while (cursor.row>=VIDEOTEXT_HEIGHT) {
188 memcpy(videomem,videomem+VIDEOTEXT_WIDTH,VIDEOTEXT_SIZE-VIDEOTEXT_WIDTH*2);
189 memset(videomem+VIDEOTEXT_WIDTH*(VIDEOTEXT_HEIGHT-1),0,VIDEOTEXT_WIDTH*2);
190 cursor.row--;
192 return 1;
196 * Writes characters to screen
197 * @param buffer Chars to write to screen
198 * @param count How many bytes to write to screen
199 * @param dev Device to write to
200 * @return How many bytes written
202 ssize_t onwrite(devfs_dev_t *dev,void *buffer,size_t count,off_t offset) {
203 int i;
204 int w = 0;
205 for (i=0;i<count;i++) w += printchar(((char*)buffer)[i]);
206 return w;
210 * Initializes screen driver
211 * @return 0=success; -1=failure
213 int init_screen() {
214 videomem = mem_getvga();
215 if (videomem==NULL) return -1;
216 memset(&saved_cursor,0,sizeof(saved_cursor));
217 default_settings();
218 clearscreen();
219 return 0;