source: mainline/kernel/genarch/src/drivers/ega/ega.c

Last change on this file was 39e1b9a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 2 months ago

Convert console output devices to batch printing

  • Property mode set to 100644
File size: 12.8 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
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/** @addtogroup kernel_genarch
30 * @{
31 */
32/**
33 * @file
34 * @brief EGA driver.
35 */
36
37#include <debug.h>
38#include <genarch/drivers/ega/ega.h>
39#include <mm/km.h>
40#include <mm/as.h>
41#include <stdlib.h>
42#include <typedefs.h>
43#include <arch/asm.h>
44#include <memw.h>
45#include <str.h>
46#include <console/chardev.h>
47#include <console/console.h>
48#include <sysinfo/sysinfo.h>
49#include <ddi/ddi.h>
50
51/*
52 * The EGA driver.
53 * Simple and short. Function for displaying characters and "scrolling".
54 */
55
56#define SPACE 0x20
57#define STYLE 0x1e
58#define INVAL 0x17
59
60#define EMPTY_CHAR ((STYLE << 8) | SPACE)
61
62typedef struct {
63 IRQ_SPINLOCK_DECLARE(lock);
64
65 parea_t parea;
66
67 uint32_t cursor;
68 uint8_t *addr;
69 uint8_t *backbuf;
70 ioport8_t *base;
71 mbstate_t mbstate;
72} ega_instance_t;
73
74static void ega_write(outdev_t *, const char *, size_t);
75static void ega_redraw(outdev_t *);
76
77static outdev_operations_t egadev_ops = {
78 .write = ega_write,
79 .redraw = ega_redraw,
80 .scroll_up = NULL,
81 .scroll_down = NULL
82};
83
84static uint16_t ega_oem_glyph(const char32_t ch)
85{
86 if (ch <= 0x007f)
87 return ch;
88
89 if (ch == 0x00a0)
90 return 255;
91
92 if (ch == 0x00a1)
93 return 173;
94
95 if ((ch >= 0x00a2) && (ch <= 0x00a3))
96 return (ch - 7);
97
98 if (ch == 0x00a5)
99 return 157;
100
101 if (ch == 0x00aa)
102 return 166;
103
104 if (ch == 0x00ab)
105 return 174;
106
107 if (ch == 0x00ac)
108 return 170;
109
110 if (ch == 0x00b0)
111 return 248;
112
113 if (ch == 0x00b1)
114 return 241;
115
116 if (ch == 0x00b2)
117 return 253;
118
119 if (ch == 0x00b5)
120 return 230;
121
122 if (ch == 0x00b7)
123 return 250;
124
125 if (ch == 0x00ba)
126 return 167;
127
128 if (ch == 0x00bb)
129 return 175;
130
131 if (ch == 0x00bc)
132 return 172;
133
134 if (ch == 0x00bd)
135 return 171;
136
137 if (ch == 0x00bf)
138 return 168;
139
140 if ((ch >= 0x00c4) && (ch <= 0x00c5))
141 return (ch - 54);
142
143 if (ch == 0x00c6)
144 return 146;
145
146 if (ch == 0x00c7)
147 return 128;
148
149 if (ch == 0x00c9)
150 return 144;
151
152 if (ch == 0x00d1)
153 return 165;
154
155 if (ch == 0x00d6)
156 return 153;
157
158 if (ch == 0x00dc)
159 return 154;
160
161 if (ch == 0x00df)
162 return 225;
163
164 if (ch == 0x00e0)
165 return 133;
166
167 if (ch == 0x00e1)
168 return 160;
169
170 if (ch == 0x00e2)
171 return 131;
172
173 if (ch == 0x00e4)
174 return 132;
175
176 if (ch == 0x00e5)
177 return 134;
178
179 if (ch == 0x00e6)
180 return 145;
181
182 if (ch == 0x00e7)
183 return 135;
184
185 if (ch == 0x00e8)
186 return 138;
187
188 if (ch == 0x00e9)
189 return 130;
190
191 if ((ch >= 0x00ea) && (ch <= 0x00eb))
192 return (ch - 98);
193
194 if (ch == 0x00ec)
195 return 141;
196
197 if (ch == 0x00ed)
198 return 161;
199
200 if (ch == 0x00ee)
201 return 140;
202
203 if (ch == 0x00ef)
204 return 139;
205
206 if (ch == 0x00f1)
207 return 164;
208
209 if (ch == 0x00f2)
210 return 149;
211
212 if (ch == 0x00f3)
213 return 162;
214
215 if (ch == 0x00f4)
216 return 147;
217
218 if (ch == 0x00f6)
219 return 148;
220
221 if (ch == 0x00f7)
222 return 246;
223
224 if (ch == 0x00f9)
225 return 151;
226
227 if (ch == 0x00fa)
228 return 163;
229
230 if (ch == 0x00fb)
231 return 150;
232
233 if (ch == 0x00fc)
234 return 129;
235
236 if (ch == 0x00ff)
237 return 152;
238
239 if (ch == 0x0192)
240 return 159;
241
242 if (ch == 0x0393)
243 return 226;
244
245 if (ch == 0x0398)
246 return 233;
247
248 if (ch == 0x03a3)
249 return 228;
250
251 if (ch == 0x03a6)
252 return 232;
253
254 if (ch == 0x03a9)
255 return 234;
256
257 if (ch == 0x03b1)
258 return 224;
259
260 if (ch == 0x03b4)
261 return 235;
262
263 if (ch == 0x03b5)
264 return 238;
265
266 if (ch == 0x03c0)
267 return 227;
268
269 if (ch == 0x03c3)
270 return 229;
271
272 if (ch == 0x03c4)
273 return 231;
274
275 if (ch == 0x03c6)
276 return 237;
277
278 if (ch == 0x207f)
279 return 252;
280
281 if (ch == 0x20a7)
282 return 158;
283
284 if (ch == 0x2219)
285 return 249;
286
287 if (ch == 0x221a)
288 return 251;
289
290 if (ch == 0x221e)
291 return 236;
292
293 if (ch == 0x2229)
294 return 239;
295
296 if (ch == 0x2248)
297 return 247;
298
299 if (ch == 0x2261)
300 return 240;
301
302 if (ch == 0x2264)
303 return 243;
304
305 if (ch == 0x2265)
306 return 242;
307
308 if (ch == 0x2310)
309 return 169;
310
311 if ((ch >= 0x2320) && (ch <= 0x2321))
312 return (ch - 8748);
313
314 if (ch == 0x2500)
315 return 196;
316
317 if (ch == 0x2502)
318 return 179;
319
320 if (ch == 0x250c)
321 return 218;
322
323 if (ch == 0x2510)
324 return 191;
325
326 if (ch == 0x2514)
327 return 192;
328
329 if (ch == 0x2518)
330 return 217;
331
332 if (ch == 0x251c)
333 return 195;
334
335 if (ch == 0x2524)
336 return 180;
337
338 if (ch == 0x252c)
339 return 194;
340
341 if (ch == 0x2534)
342 return 193;
343
344 if (ch == 0x253c)
345 return 197;
346
347 if (ch == 0x2550)
348 return 205;
349
350 if (ch == 0x2551)
351 return 186;
352
353 if ((ch >= 0x2552) && (ch <= 0x2553))
354 return (ch - 9341);
355
356 if (ch == 0x2554)
357 return 201;
358
359 if (ch == 0x2555)
360 return 184;
361
362 if (ch == 0x2556)
363 return 183;
364
365 if (ch == 0x2557)
366 return 187;
367
368 if (ch == 0x2558)
369 return 212;
370
371 if (ch == 0x2559)
372 return 211;
373
374 if (ch == 0x255a)
375 return 200;
376
377 if (ch == 0x255b)
378 return 190;
379
380 if (ch == 0x255c)
381 return 189;
382
383 if (ch == 0x255d)
384 return 188;
385
386 if ((ch >= 0x255e) && (ch <= 0x255f))
387 return (ch - 9368);
388
389 if (ch == 0x2560)
390 return 204;
391
392 if ((ch >= 0x2561) && (ch <= 0x2562))
393 return (ch - 9388);
394
395 if (ch == 0x2563)
396 return 185;
397
398 if ((ch >= 0x2564) && (ch <= 0x2565))
399 return (ch - 9363);
400
401 if (ch == 0x2566)
402 return 203;
403
404 if ((ch >= 0x2567) && (ch <= 0x2568))
405 return (ch - 9368);
406
407 if (ch == 0x2569)
408 return 202;
409
410 if (ch == 0x256a)
411 return 216;
412
413 if (ch == 0x256b)
414 return 215;
415
416 if (ch == 0x256c)
417 return 206;
418
419 if (ch == 0x2580)
420 return 223;
421
422 if (ch == 0x2584)
423 return 220;
424
425 if (ch == 0x2588)
426 return 219;
427
428 if (ch == 0x258c)
429 return 221;
430
431 if (ch == 0x2590)
432 return 222;
433
434 if ((ch >= 0x2591) && (ch <= 0x2593))
435 return (ch - 9441);
436
437 return 256;
438}
439
440/*
441 * This function takes care of scrolling.
442 */
443static void ega_check_cursor(ega_instance_t *instance)
444{
445 if (instance->cursor < EGA_SCREEN)
446 return;
447
448 memmove((void *) instance->backbuf,
449 (void *) (instance->backbuf + EGA_COLS * 2),
450 (EGA_SCREEN - EGA_COLS) * 2);
451 memsetw(instance->backbuf + (EGA_SCREEN - EGA_COLS) * 2,
452 EGA_COLS, EMPTY_CHAR);
453
454 if ((!instance->parea.mapped) || (console_override)) {
455 memmove((void *) instance->addr,
456 (void *) (instance->addr + EGA_COLS * 2),
457 (EGA_SCREEN - EGA_COLS) * 2);
458 memsetw(instance->addr + (EGA_SCREEN - EGA_COLS) * 2,
459 EGA_COLS, EMPTY_CHAR);
460 }
461
462 instance->cursor = instance->cursor - EGA_COLS;
463}
464
465static void ega_show_cursor(ega_instance_t *instance)
466{
467 if ((!instance->parea.mapped) || (console_override)) {
468 pio_write_8(instance->base + EGA_INDEX_REG, 0x0a);
469 uint8_t stat = pio_read_8(instance->base + EGA_DATA_REG);
470 pio_write_8(instance->base + EGA_INDEX_REG, 0x0a);
471 pio_write_8(instance->base + EGA_DATA_REG, stat & (~(1 << 5)));
472 }
473}
474
475static void ega_move_cursor(ega_instance_t *instance)
476{
477 if ((!instance->parea.mapped) || (console_override)) {
478 pio_write_8(instance->base + EGA_INDEX_REG, 0x0e);
479 pio_write_8(instance->base + EGA_DATA_REG,
480 (uint8_t) ((instance->cursor >> 8) & 0xff));
481 pio_write_8(instance->base + EGA_INDEX_REG, 0x0f);
482 pio_write_8(instance->base + EGA_DATA_REG,
483 (uint8_t) (instance->cursor & 0xff));
484 }
485}
486
487static void ega_sync_cursor(ega_instance_t *instance)
488{
489 if ((!instance->parea.mapped) || (console_override)) {
490 pio_write_8(instance->base + EGA_INDEX_REG, 0x0e);
491 uint8_t hi = pio_read_8(instance->base + EGA_DATA_REG);
492 pio_write_8(instance->base + EGA_INDEX_REG, 0x0f);
493 uint8_t lo = pio_read_8(instance->base + EGA_DATA_REG);
494
495 instance->cursor = (hi << 8) | lo;
496 } else
497 instance->cursor = 0;
498
499 if (instance->cursor >= EGA_SCREEN)
500 instance->cursor = 0;
501
502 if ((instance->cursor % EGA_COLS) != 0)
503 instance->cursor =
504 (instance->cursor + EGA_COLS) - instance->cursor % EGA_COLS;
505
506 memsetw(instance->backbuf + instance->cursor * 2,
507 EGA_SCREEN - instance->cursor, EMPTY_CHAR);
508
509 if ((!instance->parea.mapped) || (console_override))
510 memsetw(instance->addr + instance->cursor * 2,
511 EGA_SCREEN - instance->cursor, EMPTY_CHAR);
512
513 ega_check_cursor(instance);
514 ega_move_cursor(instance);
515 ega_show_cursor(instance);
516}
517
518static void ega_display_wchar(ega_instance_t *instance, char32_t ch)
519{
520 uint16_t index = ega_oem_glyph(ch);
521 uint8_t glyph;
522 uint8_t style;
523
524 if ((index >> 8)) {
525 glyph = U_SPECIAL;
526 style = INVAL;
527 } else {
528 glyph = index & 0xff;
529 style = STYLE;
530 }
531
532 instance->backbuf[instance->cursor * 2] = glyph;
533 instance->backbuf[instance->cursor * 2 + 1] = style;
534
535 if ((!instance->parea.mapped) || (console_override)) {
536 instance->addr[instance->cursor * 2] = glyph;
537 instance->addr[instance->cursor * 2 + 1] = style;
538 }
539}
540
541static void _putuchar(ega_instance_t *instance, char32_t ch)
542{
543 switch (ch) {
544 case '\n':
545 instance->cursor = (instance->cursor + EGA_COLS) -
546 instance->cursor % EGA_COLS;
547 break;
548 case '\t':
549 instance->cursor = (instance->cursor + 8) -
550 instance->cursor % 8;
551 break;
552 case '\b':
553 if (instance->cursor % EGA_COLS)
554 instance->cursor--;
555 break;
556 default:
557 ega_display_wchar(instance, ch);
558 instance->cursor++;
559 break;
560 }
561 ega_check_cursor(instance);
562 ega_move_cursor(instance);
563}
564
565static void ega_write(outdev_t *dev, const char *s, size_t n)
566{
567 ega_instance_t *instance = (ega_instance_t *) dev->data;
568
569 irq_spinlock_lock(&instance->lock, true);
570
571 size_t offset = 0;
572 char32_t ch;
573
574 while ((ch = str_decode_r(s, &offset, n, U_SPECIAL, &instance->mbstate)))
575 _putuchar(instance, ch);
576
577 irq_spinlock_unlock(&instance->lock, true);
578}
579
580static void ega_redraw_internal(ega_instance_t *instance)
581{
582 memcpy(instance->addr, instance->backbuf, EGA_VRAM_SIZE);
583 ega_move_cursor(instance);
584 ega_show_cursor(instance);
585}
586
587static void ega_redraw(outdev_t *dev)
588{
589 ega_instance_t *instance = (ega_instance_t *) dev->data;
590
591 irq_spinlock_lock(&instance->lock, true);
592 ega_redraw_internal(instance);
593 irq_spinlock_unlock(&instance->lock, true);
594}
595
596/** EGA was mapped or unmapped.
597 *
598 * @param arg EGA instance
599 */
600static void ega_mapped_changed(void *arg)
601{
602 ega_instance_t *instance = (ega_instance_t *) arg;
603
604 if (!instance->parea.mapped) {
605 irq_spinlock_lock(&instance->lock, true);
606 ega_redraw_internal(instance);
607 irq_spinlock_unlock(&instance->lock, true);
608 }
609}
610
611outdev_t *ega_init(ioport8_t *base, uintptr_t addr)
612{
613 outdev_t *egadev = malloc(sizeof(outdev_t));
614 if (!egadev)
615 return NULL;
616
617 ega_instance_t *instance = malloc(sizeof(ega_instance_t));
618 if (!instance) {
619 free(egadev);
620 return NULL;
621 }
622
623 outdev_initialize("egadev", egadev, &egadev_ops);
624 egadev->data = instance;
625
626 irq_spinlock_initialize(&instance->lock, "*ega.instance.lock");
627
628 instance->base = base;
629 instance->addr = (uint8_t *) km_map(addr, EGA_VRAM_SIZE,
630 KM_NATURAL_ALIGNMENT, PAGE_WRITE | PAGE_NOT_CACHEABLE);
631 if (!instance->addr) {
632 LOG("Unable to EGA video memory.");
633 free(instance);
634 free(egadev);
635 return NULL;
636 }
637
638 instance->backbuf = (uint8_t *) malloc(EGA_VRAM_SIZE);
639 if (!instance->backbuf) {
640 LOG("Unable to allocate backbuffer.");
641 free(instance);
642 free(egadev);
643 return NULL;
644 }
645
646 ddi_parea_init(&instance->parea);
647 instance->parea.pbase = addr;
648 instance->parea.frames = SIZE2FRAMES(EGA_VRAM_SIZE);
649 instance->parea.unpriv = false;
650 instance->parea.mapped = false;
651 instance->parea.mapped_changed = ega_mapped_changed;
652 instance->parea.arg = (void *) instance;
653 ddi_parea_register(&instance->parea);
654
655 /* Synchronize the back buffer and cursor position. */
656 memcpy(instance->backbuf, instance->addr, EGA_VRAM_SIZE);
657 ega_sync_cursor(instance);
658
659 if (!fb_exported) {
660 /*
661 * We export the kernel framebuffer for uspace usage.
662 * This is used in the case the uspace framebuffer
663 * driver is not self-sufficient.
664 */
665 sysinfo_set_item_val("fb", NULL, true);
666 sysinfo_set_item_val("fb.kind", NULL, 2);
667 sysinfo_set_item_val("fb.width", NULL, EGA_COLS);
668 sysinfo_set_item_val("fb.height", NULL, EGA_ROWS);
669 sysinfo_set_item_val("fb.blinking", NULL, true);
670 sysinfo_set_item_val("fb.address.physical", NULL, addr);
671
672 fb_exported = true;
673 }
674
675 return egadev;
676}
677
678/** @}
679 */
Note: See TracBrowser for help on using the repository browser.