+libm
[meinos.git] / apps / console / screen.c
blob8aec9b40be3db2007f0d84f2ccf5222a609ad948
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 * Updates hardware cursor
76 static void update_hwcursor() {
77 uint32_t pos = cursor.row*VIDEOTEXT_WIDTH+cursor.col;
78 outb(0x3D4,15);
79 outb(0x3D5,pos);
80 outb(0x3D4,14);
81 outb(0x3D5,pos>>8);
84 /**
85 * Clears screen
87 static void clearscreen() {
88 size_t i;
89 for (i=0;i<VIDEOTEXT_WIDTH*VIDEOTEXT_HEIGHT;i++) videomem[i] = VIDEOTEXT_STDCOLOR<<8;
90 cursor.col = VIDEOTEXT_STDCOL;
91 cursor.row = VIDEOTEXT_STDROW;
92 update_hwcursor();
95 /**
96 * Sets default settings
98 static void default_settings() {
99 settings.linewrap = 1;
100 settings.bell_freq = 440;
101 settings.bell_dur = 100;
102 settings.color = VIDEOTEXT_STDCOLOR;
106 * Prints a character on screen
107 * @param chr Character
109 static int printchar(char chr) {
110 size_t pos = cursor_offset();
111 static int escape = 0;
112 static char escape_buf[32];
114 if (escape) {
115 escape_buf[(escape++)-1] = chr; // put byte in escape buffer
117 if (isalpha(chr)) { // escape code finished
118 if (escape==1 && escape_buf[0]=='c') default_settings(); // reset device
119 else if (escape==3 && memcmp(escape_buf,"[7h",3)==0) settings.linewrap = 1; // enable linewrap
120 else if (escape==3 && memcmp(escape_buf,"[7l",3)==0) settings.linewrap = 0; // disable linewrap
121 else if (escape_buf[0]=='[' && (escape_buf[escape-2]=='H' || escape_buf[escape-2]=='f')) { // set cursor position
122 int row = -1;
123 int col = -1;
124 if (escape>3) sscanf(escape_buf,escape_buf[escape-2]=='H'?"[%d;%dH":"[%d;%df",&row,&col);
125 if (row!=-1 && col!=-1) {
126 cursor.col = col;
127 cursor.row = row;
129 else {
130 cursor.col = 0;
131 cursor.row = 0;
134 else if (escape_buf[0]=='[' && escape_buf[escape-2]=='A') {
135 int up = 1;
136 if (escape>3) sscanf(escape_buf,"[%dA",&up);
137 if (cursor.row>0) cursor.row -= up;
139 else if (escape_buf[0]=='[' && escape_buf[escape-2]=='B') {
140 int down = 1;
141 if (escape>3) sscanf(escape_buf,"[%dB",&down);
142 if (cursor.row<VIDEOTEXT_HEIGHT) cursor.row += down;
144 else if (escape_buf[0]=='[' && escape_buf[escape-2]=='C') {
145 int left = 1;
146 if (escape>3) sscanf(escape_buf,"[%dC",&left);
147 if (cursor.col>0) cursor.col -= left;
149 else if (escape_buf[0]=='[' && escape_buf[escape-2]=='D') {
150 int right = 1;
151 if (escape>3) sscanf(escape_buf,"[%dD",&right);
152 if (cursor.col<VIDEOTEXT_WIDTH) cursor.col += right;
154 else if (escape_buf[0]=='[' && (escape_buf[1]=='s' || escape_buf[1]=='7')) {
155 memcpy(&saved_cursor,&cursor,sizeof(cursor));
157 else if (escape_buf[0]=='[' && (escape_buf[1]=='u' || escape_buf[1]=='8')) {
158 memcpy(&cursor,&saved_cursor,sizeof(cursor));
160 else if (memcmp(escape_buf,"[K",2)==0) {
161 memset(videomem+pos,0,(VIDEOTEXT_WIDTH-cursor.col+1)*2);
163 else if (memcmp(escape_buf,"[1K",3)==0) {
164 memset(videomem+VIDEOTEXT_WIDTH*cursor.col,0,cursor.row*2);
166 else if (memcmp(escape_buf,"[2K",3)==0) {
167 memset(videomem+VIDEOTEXT_WIDTH*cursor.col,0,VIDEOTEXT_WIDTH);
169 else if (memcmp(escape_buf,"[J",2)==0) {
170 memset(videomem+VIDEOTEXT_WIDTH*cursor.col,0,(VIDEOTEXT_HEIGHT-cursor.row)*VIDEOTEXT_WIDTH*2);
172 else if (memcmp(escape_buf,"[1J",3)==0) {
173 memset(videomem,0,cursor.row*VIDEOTEXT_WIDTH*2);
175 else if (memcmp(escape_buf,"[2J",3)==0) {
176 clearscreen();
178 escape = 0;
181 else if (chr=='\a') bell(settings.bell_freq,settings.bell_dur);
182 else if (chr=='\b') cursor.col = (cursor.col-1>0)?(cursor.col-1):0;
183 else if (chr=='\t') cursor.col = cursor.col+5;
184 else if (chr=='\n') {
185 cursor.row++;
186 cursor.col = VIDEOTEXT_STDCOL;
188 else if (chr=='\f') clearscreen();
189 else if (chr=='\r') cursor.col = VIDEOTEXT_STDCOL;
190 else if (chr==0x1B) escape = 1;
191 else if (chr>=' ') {
192 *(videomem+pos) = (((uint16_t)settings.color)<<8)|chr;
193 cursor.col++;
196 if (cursor.col>=VIDEOTEXT_WIDTH) {
197 cursor.col = cursor.col-VIDEOTEXT_WIDTH;
198 cursor.row++;
200 while (cursor.row>=VIDEOTEXT_HEIGHT) {
201 memcpy(videomem,videomem+VIDEOTEXT_WIDTH,VIDEOTEXT_SIZE-VIDEOTEXT_WIDTH*2);
202 memset(videomem+VIDEOTEXT_WIDTH*(VIDEOTEXT_HEIGHT-1),0,VIDEOTEXT_WIDTH*2);
203 cursor.row--;
206 update_hwcursor();
208 return 1;
212 * Writes characters to screen
213 * @param buffer Chars to write to screen
214 * @param count How many bytes to write to screen
215 * @param dev Device to write to
216 * @return How many bytes written
218 ssize_t onwrite(devfs_dev_t *dev,void *buffer,size_t count,off_t offset) {
219 int i;
220 int w = 0;
221 for (i=0;i<count;i++) w += printchar(((char*)buffer)[i]);
222 return w;
226 * Initializes screen driver
227 * @return 0=success; -1=failure
229 int init_screen() {
230 videomem = mem_getvga();
231 if (videomem==NULL) return -1;
232 memset(&saved_cursor,0,sizeof(saved_cursor));
233 default_settings();
234 clearscreen();
235 return 0;