source: mainline/uspace/srv/fb/ega.c@ 198a9ef

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 198a9ef was 198a9ef, checked in by Jiri Svoboda <jirik.svoboda@…>, 17 years ago

Make EGA fb driver handle colors correctly when servicing a DRAW_TEXT_DATA request.

  • Property mode set to 100644
File size: 9.1 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @defgroup egafb EGA framebuffer
30 * @brief HelenOS EGA framebuffer.
31 * @ingroup fbs
32 * @{
33 */
34/** @file
35 */
36
37#include <stdlib.h>
38#include <unistd.h>
39#include <align.h>
40#include <async.h>
41#include <ipc/ipc.h>
42#include <errno.h>
43#include <stdio.h>
44#include <ddi.h>
45#include <sysinfo.h>
46#include <as.h>
47#include <ipc/fb.h>
48#include <ipc/ipc.h>
49#include <ipc/ns.h>
50#include <ipc/services.h>
51#include <libarch/ddi.h>
52#include <console/style.h>
53#include <console/color.h>
54
55#include "ega.h"
56#include "../console/screenbuffer.h"
57#include "main.h"
58
59#define MAX_SAVED_SCREENS 256
60typedef struct saved_screen {
61 short *data;
62} saved_screen;
63
64saved_screen saved_screens[MAX_SAVED_SCREENS];
65
66#define EGA_IO_ADDRESS 0x3d4
67#define EGA_IO_SIZE 2
68
69int ega_normal_color = 0x0f;
70int ega_inverted_color = 0xf0;
71
72#define NORMAL_COLOR ega_normal_color
73#define INVERTED_COLOR ega_inverted_color
74
75/* Allow only 1 connection */
76static int client_connected = 0;
77
78static unsigned int scr_width;
79static unsigned int scr_height;
80static char *scr_addr;
81
82static unsigned int style;
83
84static unsigned attr_to_ega_style(const attrs_t *a);
85
86static void clrscr(void)
87{
88 int i;
89
90 for (i = 0; i < scr_width * scr_height; i++) {
91 scr_addr[i * 2] = ' ';
92 scr_addr[i * 2 + 1] = style;
93 }
94}
95
96static void cursor_goto(unsigned int row, unsigned int col)
97{
98 int ega_cursor;
99
100 ega_cursor = col + scr_width * row;
101
102 outb(EGA_IO_ADDRESS, 0xe);
103 outb(EGA_IO_ADDRESS + 1, (ega_cursor >> 8) & 0xff);
104 outb(EGA_IO_ADDRESS, 0xf);
105 outb(EGA_IO_ADDRESS + 1, ega_cursor & 0xff);
106}
107
108static void cursor_disable(void)
109{
110 uint8_t stat;
111
112 outb(EGA_IO_ADDRESS, 0xa);
113 stat=inb(EGA_IO_ADDRESS + 1);
114 outb(EGA_IO_ADDRESS, 0xa);
115 outb(EGA_IO_ADDRESS + 1, stat | (1 << 5));
116}
117
118static void cursor_enable(void)
119{
120 uint8_t stat;
121
122 outb(EGA_IO_ADDRESS, 0xa);
123 stat=inb(EGA_IO_ADDRESS + 1);
124 outb(EGA_IO_ADDRESS, 0xa);
125 outb(EGA_IO_ADDRESS + 1, stat & (~(1 << 5)));
126}
127
128static void scroll(int rows)
129{
130 int i;
131 if (rows > 0) {
132 memmove(scr_addr, ((char *) scr_addr) + rows * scr_width * 2,
133 scr_width * scr_height * 2 - rows * scr_width * 2);
134 for (i = 0; i < rows * scr_width; i++)
135 (((short *) scr_addr) + scr_width * scr_height - rows *
136 scr_width)[i] = ((style << 8) + ' ');
137 } else if (rows < 0) {
138 memmove(((char *)scr_addr) - rows * scr_width * 2, scr_addr,
139 scr_width * scr_height * 2 + rows * scr_width * 2);
140 for (i = 0; i < -rows * scr_width; i++)
141 ((short *)scr_addr)[i] = ((style << 8 ) + ' ');
142 }
143}
144
145static void printchar(char c, unsigned int row, unsigned int col)
146{
147 scr_addr[(row * scr_width + col) * 2] = c;
148 scr_addr[(row * scr_width + col) * 2 + 1] = style;
149
150 cursor_goto(row, col + 1);
151}
152
153static void draw_text_data(keyfield_t *data)
154{
155 int i;
156
157 for (i = 0; i < scr_width * scr_height; i++) {
158 scr_addr[i * 2] = data[i].character;
159 scr_addr[i * 2 + 1] = attr_to_ega_style(&data[i].attrs);
160 }
161}
162
163static int save_screen(void)
164{
165 int i;
166
167 for (i = 0; (i < MAX_SAVED_SCREENS) && (saved_screens[i].data); i++)
168 ;
169 if (i == MAX_SAVED_SCREENS)
170 return EINVAL;
171 if (!(saved_screens[i].data = malloc(2 * scr_width * scr_height)))
172 return ENOMEM;
173 memcpy(saved_screens[i].data, scr_addr, 2 * scr_width * scr_height);
174
175 return i;
176}
177
178static int print_screen(int i)
179{
180 if (saved_screens[i].data)
181 memcpy(scr_addr, saved_screens[i].data, 2 * scr_width *
182 scr_height);
183 else
184 return EINVAL;
185 return i;
186}
187
188static int style_to_ega_style(int style)
189{
190 unsigned int ega_style;
191
192 switch (style) {
193 case STYLE_NORMAL:
194 ega_style = INVERTED_COLOR;
195 break;
196 case STYLE_EMPHASIS:
197 ega_style = INVERTED_COLOR | 4;
198 break;
199 default:
200 return INVERTED_COLOR;
201 }
202
203 return ega_style;
204}
205
206static unsigned int color_to_ega_style(int fg_color, int bg_color, int attr)
207{
208 unsigned int style;
209
210 style = (fg_color & 7) | ((bg_color & 7) << 4);
211 if (attr & CATTR_BRIGHT)
212 style = style | 0x08;
213
214 return style;
215}
216
217static unsigned int rgb_to_ega_style(uint32_t fg, uint32_t bg)
218{
219 return (fg > bg) ? NORMAL_COLOR : INVERTED_COLOR;
220}
221
222static unsigned attr_to_ega_style(const attrs_t *a)
223{
224 switch (a->t) {
225 case at_style: return style_to_ega_style(a->a.s.style);
226 case at_rgb: return rgb_to_ega_style(a->a.r.fg_color, a->a.r.bg_color);
227 case at_idx: return color_to_ega_style(a->a.i.fg_color,
228 a->a.i.bg_color, a->a.i.flags);
229 default: return INVERTED_COLOR;
230 }
231}
232
233static void ega_client_connection(ipc_callid_t iid, ipc_call_t *icall)
234{
235 int retval;
236 ipc_callid_t callid;
237 ipc_call_t call;
238 char c;
239 unsigned int row, col;
240 int bg_color, fg_color, attr;
241 uint32_t bg_rgb, fg_rgb;
242 keyfield_t *interbuf = NULL;
243 size_t intersize = 0;
244 int i;
245
246 if (client_connected) {
247 ipc_answer_0(iid, ELIMIT);
248 return;
249 }
250 client_connected = 1;
251 ipc_answer_0(iid, EOK); /* Accept connection */
252
253 while (1) {
254 callid = async_get_call(&call);
255 switch (IPC_GET_METHOD(call)) {
256 case IPC_M_PHONE_HUNGUP:
257 client_connected = 0;
258 ipc_answer_0(callid, EOK);
259 return; /* Exit thread */
260 case IPC_M_SHARE_OUT:
261 /* We accept one area for data interchange */
262 intersize = IPC_GET_ARG2(call);
263 if (intersize >= scr_width * scr_height *
264 sizeof(*interbuf)) {
265 receive_comm_area(callid, &call,
266 (void *) &interbuf);
267 continue;
268 }
269 retval = EINVAL;
270 break;
271 case FB_DRAW_TEXT_DATA:
272 if (!interbuf) {
273 retval = EINVAL;
274 break;
275 }
276 draw_text_data(interbuf);
277 retval = 0;
278 break;
279 case FB_GET_CSIZE:
280 ipc_answer_2(callid, EOK, scr_height, scr_width);
281 continue;
282 case FB_CLEAR:
283 clrscr();
284 retval = 0;
285 break;
286 case FB_PUTCHAR:
287 c = IPC_GET_ARG1(call);
288 row = IPC_GET_ARG2(call);
289 col = IPC_GET_ARG3(call);
290 if (col >= scr_width || row >= scr_height) {
291 retval = EINVAL;
292 break;
293 }
294 printchar(c, row, col);
295 retval = 0;
296 break;
297 case FB_CURSOR_GOTO:
298 row = IPC_GET_ARG1(call);
299 col = IPC_GET_ARG2(call);
300 if (row >= scr_height || col >= scr_width) {
301 retval = EINVAL;
302 break;
303 }
304 cursor_goto(row, col);
305 retval = 0;
306 break;
307 case FB_SCROLL:
308 i = IPC_GET_ARG1(call);
309 if (i > scr_height || i < -((int) scr_height)) {
310 retval = EINVAL;
311 break;
312 }
313 scroll(i);
314 retval = 0;
315 break;
316 case FB_CURSOR_VISIBILITY:
317 if(IPC_GET_ARG1(call))
318 cursor_enable();
319 else
320 cursor_disable();
321 retval = 0;
322 break;
323 case FB_SET_STYLE:
324 style = style_to_ega_style(IPC_GET_ARG1(call));
325 retval = 0;
326 break;
327 case FB_SET_COLOR:
328 fg_color = IPC_GET_ARG1(call);
329 bg_color = IPC_GET_ARG2(call);
330 attr = IPC_GET_ARG3(call);
331 style = color_to_ega_style(fg_color, bg_color, attr);
332 retval = 0;
333 break;
334 case FB_SET_RGB_COLOR:
335 fg_rgb = IPC_GET_ARG1(call);
336 bg_rgb = IPC_GET_ARG2(call);
337 style = rgb_to_ega_style(fg_rgb, bg_rgb);
338 retval = 0;
339 break;
340 case FB_VP_DRAW_PIXMAP:
341 i = IPC_GET_ARG2(call);
342 retval = print_screen(i);
343 break;
344 case FB_VP2PIXMAP:
345 retval = save_screen();
346 break;
347 case FB_DROP_PIXMAP:
348 i = IPC_GET_ARG1(call);
349 if (i >= MAX_SAVED_SCREENS) {
350 retval = EINVAL;
351 break;
352 }
353 if (saved_screens[i].data) {
354 free(saved_screens[i].data);
355 saved_screens[i].data = NULL;
356 }
357 retval = 0;
358 break;
359
360 default:
361 retval = ENOENT;
362 }
363 ipc_answer_0(callid, retval);
364 }
365}
366
367int ega_init(void)
368{
369 void *ega_ph_addr;
370 size_t sz;
371
372 ega_ph_addr = (void *) sysinfo_value("fb.address.physical");
373 scr_width = sysinfo_value("fb.width");
374 scr_height = sysinfo_value("fb.height");
375
376 if(sysinfo_value("fb.blinking")) {
377 ega_normal_color &= 0x77;
378 ega_inverted_color &= 0x77;
379 }
380
381 style = NORMAL_COLOR;
382
383 iospace_enable(task_get_id(), (void *) EGA_IO_ADDRESS, 2);
384
385 sz = scr_width * scr_height * 2;
386 scr_addr = as_get_mappable_page(sz);
387
388 physmem_map(ega_ph_addr, scr_addr, ALIGN_UP(sz, PAGE_SIZE) >>
389 PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE);
390
391 async_set_client_connection(ega_client_connection);
392
393 return 0;
394}
395
396
397/**
398 * @}
399 */
Note: See TracBrowser for help on using the repository browser.