1 /* $NetBSD: vga.c,v 1.120 2021/08/07 16:19:12 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
5 * All rights reserved.
6 *
7 * Author: Chris G. Demetriou
8 *
9 * Permission to use, copy, modify and distribute this software and
10 * its documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie the
27 * rights to redistribute these changes.
28 */
29
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: vga.c,v 1.120 2021/08/07 16:19:12 thorpej Exp $");
32
33 #include "opt_vga.h"
34 /* for WSCONS_SUPPORT_PCVTFONTS */
35 #include "opt_wsdisplay_compat.h"
36 /* for WSDISPLAY_CUSTOM_BORDER */
37 #include "opt_wsdisplay_border.h"
38 /* for WSDISPLAY_CUSTOM_OUTPUT */
39 #include "opt_wsmsgattrs.h"
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/callout.h>
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 #include <sys/malloc.h>
47 #include <sys/queue.h>
48 #include <sys/bus.h>
49
50 #include <dev/ic/mc6845reg.h>
51 #include <dev/ic/pcdisplayvar.h>
52 #include <dev/ic/vgareg.h>
53 #include <dev/ic/vgavar.h>
54
55 #include <dev/wscons/wsdisplayvar.h>
56 #include <dev/wscons/wsconsio.h>
57 #include <dev/wscons/unicode.h>
58 #include <dev/wsfont/wsfont.h>
59
60 #include <dev/ic/pcdisplay.h>
61
62 int vga_no_builtinfont = 0;
63
64 static struct wsdisplay_font _vga_builtinfont = {
65 "builtin", /* typeface name */
66 0, /* firstchar */
67 256, /* numbers */
68 WSDISPLAY_FONTENC_IBM, /* encoding */
69 8, /* width */
70 16, /* height */
71 1, /* stride */
72 WSDISPLAY_FONTORDER_L2R, /* bit order */
73 0, /* byte order */
74 NULL /* data */
75 };
76
77 struct egavga_font {
78 struct wsdisplay_font *wsfont;
79 int cookie; /* wsfont handle, -1 invalid */
80 int slot; /* in adapter RAM */
81 int usecount;
82 TAILQ_ENTRY(egavga_font) next; /* LRU queue */
83 };
84
85 static struct egavga_font vga_builtinfont = {
86 .wsfont = &_vga_builtinfont,
87 .cookie = -1,
88 .slot = 0,
89 };
90
91 #ifdef VGA_CONSOLE_SCREENTYPE
92 static struct egavga_font vga_consolefont;
93 #endif
94
95 struct vgascreen {
96 struct pcdisplayscreen pcs;
97
98 LIST_ENTRY(vgascreen) next;
99
100 struct vga_config *cfg;
101
102 /* videostate */
103 struct egavga_font *fontset1, *fontset2;
104 /* font data */
105
106 int mindispoffset, maxdispoffset;
107 int vga_rollover;
108 int visibleoffset;
109 };
110
111 static int vgaconsole, vga_console_type, vga_console_attached;
112 static struct vgascreen vga_console_screen;
113 static struct vga_config vga_console_vc;
114
115 static struct egavga_font *egavga_getfont(struct vga_config *, struct vgascreen *,
116 const char *, int);
117 static void egavga_unreffont(struct vga_config *, struct egavga_font *);
118
119 static int vga_selectfont(struct vga_config *, struct vgascreen *, const char *,
120 const char *);
121 static void vga_init_screen(struct vga_config *, struct vgascreen *,
122 const struct wsscreen_descr *, int, long *);
123 static void vga_init(struct vga_config *, bus_space_tag_t, bus_space_tag_t);
124 static void vga_setfont(struct vga_config *, struct vgascreen *);
125
126 static int vga_mapchar(void *, int, unsigned int *);
127 static void vga_putchar(void *, int, int, u_int, long);
128 static int vga_allocattr(void *, int, int, int, long *);
129 static void vga_copyrows(void *, int, int, int);
130 #ifdef WSDISPLAY_SCROLLSUPPORT
131 static void vga_scroll (void *, void *, int);
132 #endif
133
134 const struct wsdisplay_emulops vga_emulops = {
135 pcdisplay_cursor,
136 vga_mapchar,
137 vga_putchar,
138 pcdisplay_copycols,
139 pcdisplay_erasecols,
140 vga_copyrows,
141 pcdisplay_eraserows,
142 vga_allocattr,
143 #ifdef WSDISPLAY_CUSTOM_OUTPUT
144 pcdisplay_replaceattr,
145 #else
146 NULL,
147 #endif
148 };
149
150 /*
151 * translate WS(=ANSI) color codes to standard pc ones
152 */
153 static const unsigned char fgansitopc[] = {
154 #ifdef __alpha__
155 /*
156 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!!
157 * XXX We should probably not bother with this
158 * XXX (reinitialize the palette registers).
159 */
160 FG_BLACK, FG_BLUE, FG_GREEN, FG_CYAN, FG_RED,
161 FG_MAGENTA, FG_BROWN, FG_LIGHTGREY
162 #else
163 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
164 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
165 #endif
166 }, bgansitopc[] = {
167 #ifdef __alpha__
168 BG_BLACK, BG_BLUE, BG_GREEN, BG_CYAN, BG_RED,
169 BG_MAGENTA, BG_BROWN, BG_LIGHTGREY
170 #else
171 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
172 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
173 #endif
174 };
175
176 const struct wsscreen_descr vga_25lscreen = {
177 "80x25", 80, 25,
178 &vga_emulops,
179 8, 16,
180 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
181 NULL,
182 }, vga_25lscreen_mono = {
183 "80x25", 80, 25,
184 &vga_emulops,
185 8, 16,
186 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
187 NULL,
188 }, vga_25lscreen_bf = {
189 "80x25bf", 80, 25,
190 &vga_emulops,
191 8, 16,
192 WSSCREEN_WSCOLORS | WSSCREEN_BLINK,
193 NULL,
194 }, vga_40lscreen = {
195 "80x40", 80, 40,
196 &vga_emulops,
197 8, 10,
198 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
199 NULL,
200 }, vga_40lscreen_mono = {
201 "80x40", 80, 40,
202 &vga_emulops,
203 8, 10,
204 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
205 NULL,
206 }, vga_40lscreen_bf = {
207 "80x40bf", 80, 40,
208 &vga_emulops,
209 8, 10,
210 WSSCREEN_WSCOLORS | WSSCREEN_BLINK,
211 NULL,
212 }, vga_50lscreen = {
213 "80x50", 80, 50,
214 &vga_emulops,
215 8, 8,
216 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
217 NULL,
218 }, vga_50lscreen_mono = {
219 "80x50", 80, 50,
220 &vga_emulops,
221 8, 8,
222 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
223 NULL,
224 }, vga_50lscreen_bf = {
225 "80x50bf", 80, 50,
226 &vga_emulops,
227 8, 8,
228 WSSCREEN_WSCOLORS | WSSCREEN_BLINK,
229 NULL,
230 }, vga_24lscreen = {
231 "80x24", 80, 24,
232 &vga_emulops,
233 8, 16,
234 WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK,
235 NULL,
236 }, vga_24lscreen_mono = {
237 "80x24", 80, 24,
238 &vga_emulops,
239 8, 16,
240 WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE,
241 NULL,
242 }, vga_24lscreen_bf = {
243 "80x24bf", 80, 24,
244 &vga_emulops,
245 8, 16,
246 WSSCREEN_WSCOLORS | WSSCREEN_BLINK,
247 NULL,
248 };
249
250 #define VGA_SCREEN_CANTWOFONTS(type) (!((type)->capabilities & WSSCREEN_HILIT))
251
252 const struct wsscreen_descr *_vga_scrlist[] = {
253 &vga_25lscreen,
254 &vga_25lscreen_bf,
255 &vga_40lscreen,
256 &vga_40lscreen_bf,
257 &vga_50lscreen,
258 &vga_50lscreen_bf,
259 &vga_24lscreen,
260 &vga_24lscreen_bf,
261 /* XXX other formats, graphics screen? */
262 }, *_vga_scrlist_mono[] = {
263 &vga_25lscreen_mono,
264 &vga_40lscreen_mono,
265 &vga_50lscreen_mono,
266 &vga_24lscreen_mono,
267 /* XXX other formats, graphics screen? */
268 };
269
270 const struct wsscreen_list vga_screenlist = {
271 sizeof(_vga_scrlist) / sizeof(struct wsscreen_descr *),
272 _vga_scrlist
273 }, vga_screenlist_mono = {
274 sizeof(_vga_scrlist_mono) / sizeof(struct wsscreen_descr *),
275 _vga_scrlist_mono
276 };
277
278 static int vga_ioctl(void *, void *, u_long, void *, int, struct lwp *);
279 static paddr_t vga_mmap(void *, void *, off_t, int);
280 static int vga_alloc_screen(void *, const struct wsscreen_descr *,
281 void **, int *, int *, long *);
282 static void vga_free_screen(void *, void *);
283 static int vga_show_screen(void *, void *, int,
284 void (*)(void *, int, int), void *);
285 static int vga_load_font(void *, void *, struct wsdisplay_font *);
286 #ifdef WSDISPLAY_CUSTOM_BORDER
287 static int vga_getborder(struct vga_config *, u_int *);
288 static int vga_setborder(struct vga_config *, u_int);
289 #endif /* WSDISPLAY_CUSTOM_BORDER */
290
291 static void vga_doswitch(struct vga_config *);
292 static void vga_save_palette(struct vga_config *);
293 static void vga_restore_palette(struct vga_config *);
294
295
296 const struct wsdisplay_accessops vga_accessops = {
297 vga_ioctl,
298 vga_mmap,
299 vga_alloc_screen,
300 vga_free_screen,
301 vga_show_screen,
302 vga_load_font,
303 NULL,
304 #ifdef WSDISPLAY_SCROLLSUPPORT
305 vga_scroll,
306 #else
307 NULL,
308 #endif
309 };
310
311 /*
312 * We want at least ASCII 32..127 be present in the
313 * first font slot.
314 */
315 #define vga_valid_primary_font(f) \
316 (f->wsfont->encoding == WSDISPLAY_FONTENC_IBM || \
317 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO || \
318 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO2 || \
319 f->wsfont->encoding == WSDISPLAY_FONTENC_ISO7 || \
320 f->wsfont->encoding == WSDISPLAY_FONTENC_KOI8_R)
321
322 static struct egavga_font *
egavga_getfont(struct vga_config * vc,struct vgascreen * scr,const char * name,int primary)323 egavga_getfont(struct vga_config *vc, struct vgascreen *scr, const char *name,
324 int primary)
325 {
326 struct egavga_font *f;
327 int cookie;
328 struct wsdisplay_font *wf;
329
330 TAILQ_FOREACH(f, &vc->vc_fontlist, next) {
331 if (wsfont_matches(f->wsfont, name,
332 8, scr->pcs.type->fontheight, 0, WSFONT_FIND_BITMAP) &&
333 (!primary || vga_valid_primary_font(f))) {
334 #ifdef VGAFONTDEBUG
335 if (scr != &vga_console_screen || vga_console_attached)
336 printf("vga_getfont: %s already present\n",
337 name ? name : "<default>");
338 #endif
339 goto found;
340 }
341 }
342
343 cookie = wsfont_find(name, 8, scr->pcs.type->fontheight, 0,
344 WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP);
345 /* XXX obey "primary" */
346 if (cookie == -1) {
347 #ifdef VGAFONTDEBUG
348 if (scr != &vga_console_screen || vga_console_attached)
349 printf("vga_getfont: %s not found\n",
350 name ? name : "<default>");
351 #endif
352 return (0);
353 }
354
355 if (wsfont_lock(cookie, &wf))
356 return (0);
357
358 #ifdef VGA_CONSOLE_SCREENTYPE
359 if (scr == &vga_console_screen)
360 f = &vga_consolefont;
361 else
362 #endif
363 f = malloc(sizeof(struct egavga_font), M_DEVBUF, M_WAITOK);
364 f->wsfont = wf;
365 f->cookie = cookie;
366 f->slot = -1; /* not yet loaded */
367 f->usecount = 0; /* incremented below */
368 TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next);
369
370 found:
371 f->usecount++;
372 #ifdef VGAFONTDEBUG
373 if (scr != &vga_console_screen || vga_console_attached)
374 printf("vga_getfont: usecount=%d\n", f->usecount);
375 #endif
376 return (f);
377 }
378
379 static void
egavga_unreffont(struct vga_config * vc,struct egavga_font * f)380 egavga_unreffont(struct vga_config *vc, struct egavga_font *f)
381 {
382
383 f->usecount--;
384 #ifdef VGAFONTDEBUG
385 printf("vga_unreffont: usecount=%d\n", f->usecount);
386 #endif
387 if (f->usecount == 0 && f->cookie != -1) {
388 TAILQ_REMOVE(&vc->vc_fontlist, f, next);
389 if (f->slot != -1) {
390 KASSERT(vc->vc_fonts[f->slot] == f);
391 vc->vc_fonts[f->slot] = 0;
392 }
393 wsfont_unlock(f->cookie);
394 #ifdef VGA_CONSOLE_SCREENTYPE
395 if (f != &vga_consolefont)
396 #endif
397 free(f, M_DEVBUF);
398 }
399 }
400
401 static int
vga_selectfont(struct vga_config * vc,struct vgascreen * scr,const char * name1,const char * name2)402 vga_selectfont(struct vga_config *vc, struct vgascreen *scr, const char *name1,
403 const char *name2)
404 {
405 const struct wsscreen_descr *type = scr->pcs.type;
406 struct egavga_font *f1, *f2;
407
408 f1 = egavga_getfont(vc, scr, name1, 1);
409 if (!f1)
410 return (ENXIO);
411
412 if (VGA_SCREEN_CANTWOFONTS(type) && name2) {
413 f2 = egavga_getfont(vc, scr, name2, 0);
414 if (!f2) {
415 egavga_unreffont(vc, f1);
416 return (ENXIO);
417 }
418 } else
419 f2 = 0;
420
421 #ifdef VGAFONTDEBUG
422 if (scr != &vga_console_screen || vga_console_attached) {
423 printf("vga (%s): font1=%s (slot %d)", type->name,
424 f1->wsfont->name, f1->slot);
425 if (f2)
426 printf(", font2=%s (slot %d)",
427 f2->wsfont->name, f2->slot);
428 printf("\n");
429 }
430 #endif
431 if (scr->fontset1)
432 egavga_unreffont(vc, scr->fontset1);
433 scr->fontset1 = f1;
434 if (scr->fontset2)
435 egavga_unreffont(vc, scr->fontset2);
436 scr->fontset2 = f2;
437 return (0);
438 }
439
440 static void
vga_init_screen(struct vga_config * vc,struct vgascreen * scr,const struct wsscreen_descr * type,int existing,long * attrp)441 vga_init_screen(struct vga_config *vc, struct vgascreen *scr,
442 const struct wsscreen_descr *type, int existing, long *attrp)
443 {
444 int cpos;
445 int res __diagused;
446
447 scr->cfg = vc;
448 scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl;
449 scr->pcs.type = type;
450 scr->pcs.active = existing;
451 scr->mindispoffset = 0;
452 if (vc->vc_quirks & VGA_QUIRK_NOFASTSCROLL)
453 scr->maxdispoffset = 0;
454 else
455 scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2;
456
457 if (existing) {
458 vc->active = scr;
459
460 cpos = vga_6845_read(&vc->hdl, cursorh) << 8;
461 cpos |= vga_6845_read(&vc->hdl, cursorl);
462
463 /* make sure we have a valid cursor position */
464 if (cpos < 0 || cpos >= type->nrows * type->ncols)
465 cpos = 0;
466
467 scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9;
468 scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1;
469
470 /* make sure we have a valid memory offset */
471 if (scr->pcs.dispoffset < scr->mindispoffset ||
472 scr->pcs.dispoffset > scr->maxdispoffset)
473 scr->pcs.dispoffset = scr->mindispoffset;
474
475 if (type != vc->currenttype) {
476 vga_setscreentype(&vc->hdl, type);
477 vc->currenttype = type;
478 }
479 } else {
480 cpos = 0;
481 scr->pcs.dispoffset = scr->mindispoffset;
482 }
483
484 scr->pcs.visibleoffset = scr->pcs.dispoffset;
485 scr->vga_rollover = 0;
486
487 scr->pcs.cursorrow = cpos / type->ncols;
488 scr->pcs.cursorcol = cpos % type->ncols;
489 pcdisplay_cursor_init(&scr->pcs, existing);
490
491 #ifdef __alpha__
492 if (!vc->hdl.vh_mono)
493 /*
494 * DEC firmware uses a blue background.
495 * XXX These should be specified as kernel options for
496 * XXX alpha only, not hardcoded here (which is wrong
497 * XXX anyway because the emulation layer will assume
498 * XXX the default attribute is white on black).
499 */
500 res = vga_allocattr(scr, WSCOL_WHITE, WSCOL_BLUE,
501 WSATTR_WSCOLORS, attrp);
502 else
503 #endif
504 res = vga_allocattr(scr, 0, 0, 0, attrp);
505 #ifdef DIAGNOSTIC
506 if (res)
507 panic("vga_init_screen: attribute botch");
508 #endif
509
510 scr->pcs.mem = NULL;
511
512 scr->fontset1 = scr->fontset2 = 0;
513 if (vga_selectfont(vc, scr, 0, 0)) {
514 if (scr == &vga_console_screen)
515 panic("vga_init_screen: no font");
516 else
517 printf("vga_init_screen: no font\n");
518 }
519 if (existing)
520 vga_setfont(vc, scr);
521
522 vc->nscreens++;
523 LIST_INSERT_HEAD(&vc->screens, scr, next);
524 }
525
526 static void
vga_init(struct vga_config * vc,bus_space_tag_t iot,bus_space_tag_t memt)527 vga_init(struct vga_config *vc, bus_space_tag_t iot, bus_space_tag_t memt)
528 {
529 struct vga_handle *vh = &vc->hdl;
530 uint8_t mor;
531 int i;
532
533 vh->vh_iot = iot;
534 vh->vh_memt = memt;
535
536 if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga))
537 panic("vga_init: couldn't map vga io");
538
539 /* read "misc output register" */
540 mor = vga_raw_read(vh, VGA_MISC_DATAR);
541 vh->vh_mono = !(mor & 1);
542
543 if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0,
544 &vh->vh_ioh_6845))
545 panic("vga_init: couldn't map 6845 io");
546
547 if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000,
548 BUS_SPACE_MAP_CACHEABLE, &vh->vh_allmemh))
549 panic("vga_init: couldn't map memory");
550
551 if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh,
552 (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, &vh->vh_memh))
553 panic("vga_init: mem subrange failed");
554
555 vc->nscreens = 0;
556 LIST_INIT(&vc->screens);
557 vc->active = NULL;
558 vc->currenttype = vh->vh_mono ? &vga_25lscreen_mono : &vga_25lscreen;
559 callout_init(&vc->vc_switch_callout, 0);
560
561 wsfont_init();
562 if (vga_no_builtinfont) {
563 struct wsdisplay_font *wf;
564 int cookie;
565
566 cookie = wsfont_find(NULL, 8, 16, 0,
567 WSDISPLAY_FONTORDER_L2R, 0, WSFONT_FIND_BITMAP);
568 if (cookie == -1 || wsfont_lock(cookie, &wf))
569 panic("vga_init: can't load console font");
570 vga_loadchars(&vc->hdl, 0, wf->firstchar, wf->numchars,
571 wf->fontheight, wf->data);
572 vga_builtinfont.wsfont = wf;
573 vga_builtinfont.cookie = cookie;
574 vga_builtinfont.slot = 0;
575 }
576 vc->vc_fonts[0] = &vga_builtinfont;
577 for (i = 1; i < 8; i++)
578 vc->vc_fonts[i] = 0;
579 TAILQ_INIT(&vc->vc_fontlist);
580 TAILQ_INSERT_HEAD(&vc->vc_fontlist, &vga_builtinfont, next);
581
582 vc->currentfontset1 = vc->currentfontset2 = 0;
583
584 if (!vh->vh_mono && (u_int)WSDISPLAY_BORDER_COLOR < sizeof(fgansitopc))
585 _vga_attr_write(vh, VGA_ATC_OVERSCAN,
586 fgansitopc[WSDISPLAY_BORDER_COLOR]);
587 vga_save_palette(vc);
588 }
589
590 void
vga_common_attach(struct vga_softc * sc,bus_space_tag_t iot,bus_space_tag_t memt,int type,int quirks,const struct vga_funcs * vf)591 vga_common_attach(struct vga_softc *sc, bus_space_tag_t iot,
592 bus_space_tag_t memt, int type, int quirks,
593 const struct vga_funcs *vf)
594 {
595 int console;
596 struct vga_config *vc;
597 struct wsemuldisplaydev_attach_args aa;
598
599 console = vga_is_console(iot, type);
600
601 if (console) {
602 vc = &vga_console_vc;
603 vga_console_attached = 1;
604 } else {
605 vc = malloc(sizeof(struct vga_config), M_DEVBUF, M_WAITOK);
606 vga_init(vc, iot, memt);
607 }
608
609 if (quirks & VGA_QUIRK_ONEFONT) {
610 vc->vc_nfontslots = 1;
611 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL
612 /*
613 * XXX maybe invalidate font in slot > 0, but this can
614 * only be happen with VGA_CONSOLE_SCREENTYPE, and then
615 * we require VGA_CONSOLE_ATI_BROKEN_FONTSEL anyway.
616 */
617 #endif
618 } else {
619 vc->vc_nfontslots = 8;
620 #ifndef VGA_CONSOLE_ATI_BROKEN_FONTSEL
621 /*
622 * XXX maybe validate builtin font shifted to slot 1 if
623 * slot 0 got overwritten because of VGA_CONSOLE_SCREENTYPE,
624 * but it will be reloaded anyway if needed.
625 */
626 #endif
627 }
628
629 /*
630 * Save the builtin font to memory. In case it got overwritten
631 * in console initialization, use the copy in slot 1.
632 */
633 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL
634 #define BUILTINFONTLOC (vga_builtinfont.slot == -1 ? 1 : 0)
635 #else
636 KASSERT(vga_builtinfont.slot == 0);
637 #define BUILTINFONTLOC (0)
638 #endif
639 if (!vga_no_builtinfont) {
640 char *data =
641 malloc(256 * vga_builtinfont.wsfont->fontheight,
642 M_DEVBUF, M_WAITOK);
643 vga_readoutchars(&vc->hdl, BUILTINFONTLOC, 0, 256,
644 vga_builtinfont.wsfont->fontheight, data);
645 vga_builtinfont.wsfont->data = data;
646 }
647
648 vc->vc_type = type;
649 vc->vc_funcs = vf;
650 vc->vc_quirks = quirks;
651
652 sc->sc_vc = vc;
653 vc->softc = sc;
654
655 aa.console = console;
656 aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist);
657 aa.accessops = &vga_accessops;
658 aa.accesscookie = vc;
659
660 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint,
661 CFARGS(.iattr = "wsemuldisplaydev"));
662 }
663
664 int
vga_cnattach(bus_space_tag_t iot,bus_space_tag_t memt,int type,int check)665 vga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check)
666 {
667 long defattr;
668 const struct wsscreen_descr *scr;
669
670 if (check && !vga_common_probe(iot, memt))
671 return (ENXIO);
672
673 /* set up bus-independent VGA configuration */
674 vga_init(&vga_console_vc, iot, memt);
675 #ifdef VGA_CONSOLE_SCREENTYPE
676 scr = wsdisplay_screentype_pick(vga_console_vc.hdl.vh_mono ?
677 &vga_screenlist_mono : &vga_screenlist, VGA_CONSOLE_SCREENTYPE);
678 if (!scr)
679 panic("vga_cnattach: invalid screen type");
680 #else
681 scr = vga_console_vc.currenttype;
682 #endif
683 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL
684 /*
685 * On some (most/all?) ATI cards, only font slot 0 is usable.
686 * vga_init_screen() might need font slot 0 for a non-default
687 * console font, so save the builtin VGA font to another font slot.
688 * The attach() code will take care later.
689 */
690 vga_console_vc.vc_quirks |= VGA_QUIRK_ONEFONT; /* redundant */
691 vga_copyfont01(&vga_console_vc.hdl);
692 vga_console_vc.vc_nfontslots = 1;
693 #else
694 vga_console_vc.vc_nfontslots = 8;
695 #endif
696 #ifdef notdef
697 /* until we know better, assume "fast scrolling" does not work */
698 vga_console_vc.vc_quirks |= VGA_QUIRK_NOFASTSCROLL;
699 #endif
700
701 vga_init_screen(&vga_console_vc, &vga_console_screen, scr, 1, &defattr);
702
703 wsdisplay_cnattach(scr, &vga_console_screen,
704 vga_console_screen.pcs.cursorcol,
705 vga_console_screen.pcs.cursorrow, defattr);
706
707 vgaconsole = 1;
708 vga_console_type = type;
709 return (0);
710 }
711
712 int
vga_cndetach(void)713 vga_cndetach(void)
714 {
715 struct vga_config *vc;
716 struct vga_handle *vh;
717
718 vc = &vga_console_vc;
719 vh = &vc->hdl;
720
721 if (vgaconsole) {
722 wsdisplay_cndetach();
723
724 bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10);
725 bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10);
726 bus_space_unmap(vh->vh_memt, vh->vh_allmemh, 0x20000);
727
728 vga_console_attached = 0;
729 vgaconsole = 0;
730
731 return 1;
732 }
733
734 return 0;
735 }
736
737 int
vga_is_console(bus_space_tag_t iot,int type)738 vga_is_console(bus_space_tag_t iot, int type)
739 {
740 if (vgaconsole &&
741 !vga_console_attached &&
742 bus_space_is_equal(iot, vga_console_vc.hdl.vh_iot) &&
743 (vga_console_type == -1 || (type == vga_console_type)))
744 return (1);
745 return (0);
746 }
747
748 static int
vga_get_video(struct vga_config * vc)749 vga_get_video(struct vga_config *vc)
750 {
751
752 return (vga_ts_read(&vc->hdl, mode) & VGA_TS_MODE_BLANK) == 0;
753 }
754
755 static void
vga_set_video(struct vga_config * vc,int state)756 vga_set_video(struct vga_config *vc, int state)
757 {
758 int val;
759
760 vga_ts_write(&vc->hdl, syncreset, 0x01);
761 if (state) { /* unblank screen */
762 val = vga_ts_read(&vc->hdl, mode);
763 vga_ts_write(&vc->hdl, mode, val & ~VGA_TS_MODE_BLANK);
764 #ifndef VGA_NO_VBLANK
765 val = vga_6845_read(&vc->hdl, mode);
766 vga_6845_write(&vc->hdl, mode, val | 0x80);
767 #endif
768 } else { /* blank screen */
769 val = vga_ts_read(&vc->hdl, mode);
770 vga_ts_write(&vc->hdl, mode, val | VGA_TS_MODE_BLANK);
771 #ifndef VGA_NO_VBLANK
772 val = vga_6845_read(&vc->hdl, mode);
773 vga_6845_write(&vc->hdl, mode, val & ~0x80);
774 #endif
775 }
776 vga_ts_write(&vc->hdl, syncreset, 0x03);
777 }
778
779 static int
vga_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)780 vga_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
781 {
782 struct vga_config *vc = v;
783 struct vgascreen *scr = vs;
784 const struct vga_funcs *vf = vc->vc_funcs;
785
786 switch (cmd) {
787 case WSDISPLAYIO_SMODE:
788 if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL)
789 vga_restore_palette(vc);
790 return 0;
791
792 case WSDISPLAYIO_GTYPE:
793 *(int *)data = vc->vc_type;
794 return 0;
795
796 case WSDISPLAYIO_GINFO:
797 /* XXX should get detailed hardware information here */
798 return EPASSTHROUGH;
799
800 case WSDISPLAYIO_GVIDEO:
801 *(int *)data = (vga_get_video(vc) ?
802 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF);
803 return 0;
804
805 case WSDISPLAYIO_SVIDEO:
806 vga_set_video(vc, *(int *)data == WSDISPLAYIO_VIDEO_ON);
807 return 0;
808
809 case WSDISPLAYIO_GETWSCHAR:
810 KASSERT(scr != NULL);
811 return pcdisplay_getwschar(&scr->pcs,
812 (struct wsdisplay_char *)data);
813
814 case WSDISPLAYIO_PUTWSCHAR:
815 KASSERT(scr != NULL);
816 return pcdisplay_putwschar(&scr->pcs,
817 (struct wsdisplay_char *)data);
818
819 #ifdef WSDISPLAY_CUSTOM_BORDER
820 case WSDISPLAYIO_GBORDER:
821 return (vga_getborder(vc, (u_int *)data));
822
823 case WSDISPLAYIO_SBORDER:
824 return (vga_setborder(vc, *(u_int *)data));
825 #endif
826
827 case WSDISPLAYIO_GETCMAP:
828 case WSDISPLAYIO_PUTCMAP:
829 case WSDISPLAYIO_GCURPOS:
830 case WSDISPLAYIO_SCURPOS:
831 case WSDISPLAYIO_GCURMAX:
832 case WSDISPLAYIO_GCURSOR:
833 case WSDISPLAYIO_SCURSOR:
834 /* NONE of these operations are by the generic VGA driver. */
835 return EPASSTHROUGH;
836 }
837
838 if (vc->vc_funcs == NULL)
839 return (EPASSTHROUGH);
840
841 if (vf->vf_ioctl == NULL)
842 return (EPASSTHROUGH);
843
844 return ((*vf->vf_ioctl)(v, cmd, data, flag, l));
845 }
846
847 static paddr_t
vga_mmap(void * v,void * vs,off_t offset,int prot)848 vga_mmap(void *v, void *vs, off_t offset, int prot)
849 {
850 struct vga_config *vc = v;
851 const struct vga_funcs *vf = vc->vc_funcs;
852
853 if (vc->vc_funcs == NULL)
854 return (-1);
855
856 if (vf->vf_mmap == NULL)
857 return (-1);
858
859 return ((*vf->vf_mmap)(v, offset, prot));
860 }
861
862 static int
vga_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * defattrp)863 vga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
864 int *curxp, int *curyp, long *defattrp)
865 {
866 struct vga_config *vc = v;
867 struct vgascreen *scr;
868
869 if (vc->nscreens == 1) {
870 struct vgascreen *scr1 = vc->screens.lh_first;
871 /*
872 * When allocating the second screen, get backing store
873 * for the first one too.
874 * XXX We could be more clever and use video RAM.
875 */
876 scr1->pcs.mem =
877 malloc(scr1->pcs.type->ncols * scr1->pcs.type->nrows * 2,
878 M_DEVBUF, M_WAITOK);
879 }
880
881 scr = malloc(sizeof(struct vgascreen), M_DEVBUF, M_WAITOK);
882 vga_init_screen(vc, scr, type, vc->nscreens == 0, defattrp);
883
884 if (vc->nscreens > 1) {
885 scr->pcs.mem = malloc(type->ncols * type->nrows * 2,
886 M_DEVBUF, M_WAITOK);
887 pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp);
888 }
889
890 *cookiep = scr;
891 *curxp = scr->pcs.cursorcol;
892 *curyp = scr->pcs.cursorrow;
893
894 return (0);
895 }
896
897 static void
vga_free_screen(void * v,void * cookie)898 vga_free_screen(void *v, void *cookie)
899 {
900 struct vgascreen *vs = cookie;
901 struct vga_config *vc = vs->cfg;
902
903 LIST_REMOVE(vs, next);
904 vc->nscreens--;
905 if (vs->fontset1)
906 egavga_unreffont(vc, vs->fontset1);
907 if (vs->fontset2)
908 egavga_unreffont(vc, vs->fontset2);
909
910 if (vs != &vga_console_screen)
911 free(vs, M_DEVBUF);
912 else
913 panic("vga_free_screen: console");
914
915 if (vc->active == vs)
916 vc->active = 0;
917 }
918
919 static void vga_usefont(struct vga_config *, struct egavga_font *);
920
921 static void
vga_usefont(struct vga_config * vc,struct egavga_font * f)922 vga_usefont(struct vga_config *vc, struct egavga_font *f)
923 {
924 int slot;
925 struct egavga_font *of;
926
927 if (f->slot != -1)
928 goto toend;
929
930 for (slot = 0; slot < vc->vc_nfontslots; slot++) {
931 if (!vc->vc_fonts[slot])
932 goto loadit;
933 }
934
935 /* have to kick out another one */
936 TAILQ_FOREACH(of, &vc->vc_fontlist, next) {
937 if (of->slot != -1) {
938 KASSERT(vc->vc_fonts[of->slot] == of);
939 slot = of->slot;
940 of->slot = -1;
941 goto loadit;
942 }
943 }
944 panic("vga_usefont");
945
946 loadit:
947 vga_loadchars(&vc->hdl, slot, f->wsfont->firstchar,
948 f->wsfont->numchars, f->wsfont->fontheight, f->wsfont->data);
949 f->slot = slot;
950 vc->vc_fonts[slot] = f;
951
952 toend:
953 TAILQ_REMOVE(&vc->vc_fontlist, f, next);
954 TAILQ_INSERT_TAIL(&vc->vc_fontlist, f, next);
955 }
956
957 static void
vga_setfont(struct vga_config * vc,struct vgascreen * scr)958 vga_setfont(struct vga_config *vc, struct vgascreen *scr)
959 {
960 int fontslot1, fontslot2;
961
962 if (scr->fontset1)
963 vga_usefont(vc, scr->fontset1);
964 if (scr->fontset2)
965 vga_usefont(vc, scr->fontset2);
966
967 fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0);
968 fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1);
969 if (vc->currentfontset1 != fontslot1 ||
970 vc->currentfontset2 != fontslot2) {
971 vga_setfontset(&vc->hdl, fontslot1, fontslot2);
972 vc->currentfontset1 = fontslot1;
973 vc->currentfontset2 = fontslot2;
974 }
975 }
976
977 static int
vga_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)978 vga_show_screen(void *v, void *cookie, int waitok,
979 void (*cb)(void *, int, int), void *cbarg)
980 {
981 struct vgascreen *scr = cookie, *oldscr;
982 struct vga_config *vc = scr->cfg;
983
984 oldscr = vc->active; /* can be NULL! */
985 if (scr == oldscr) {
986 return (0);
987 }
988
989 vc->wantedscreen = cookie;
990 vc->switchcb = cb;
991 vc->switchcbarg = cbarg;
992 if (cb) {
993 callout_reset(&vc->vc_switch_callout, 0,
994 (void(*)(void *))vga_doswitch, vc);
995 return (EAGAIN);
996 }
997
998 vga_doswitch(vc);
999 return (0);
1000 }
1001
1002 static void
vga_doswitch(struct vga_config * vc)1003 vga_doswitch(struct vga_config *vc)
1004 {
1005 struct vgascreen *scr, *oldscr;
1006 struct vga_handle *vh = &vc->hdl;
1007 const struct wsscreen_descr *type;
1008
1009 scr = vc->wantedscreen;
1010 if (!scr) {
1011 printf("vga_doswitch: disappeared\n");
1012 (*vc->switchcb)(vc->switchcbarg, EIO, 0);
1013 return;
1014 }
1015 type = scr->pcs.type;
1016 oldscr = vc->active; /* can be NULL! */
1017 #ifdef DIAGNOSTIC
1018 if (oldscr) {
1019 if (!oldscr->pcs.active)
1020 panic("vga_show_screen: not active");
1021 if (oldscr->pcs.type != vc->currenttype)
1022 panic("vga_show_screen: bad type");
1023 }
1024 #endif
1025 if (scr == oldscr) {
1026 return;
1027 }
1028 #ifdef DIAGNOSTIC
1029 if (scr->pcs.active)
1030 panic("vga_show_screen: active");
1031 #endif
1032
1033 if (oldscr) {
1034 const struct wsscreen_descr *oldtype = oldscr->pcs.type;
1035
1036 oldscr->pcs.active = 0;
1037 bus_space_read_region_2(vh->vh_memt, vh->vh_memh,
1038 oldscr->pcs.dispoffset, oldscr->pcs.mem,
1039 oldtype->ncols * oldtype->nrows);
1040 }
1041
1042 if (vc->currenttype != type) {
1043 vga_setscreentype(vh, type);
1044 vc->currenttype = type;
1045 }
1046
1047 vga_setfont(vc, scr);
1048 vga_restore_palette(vc);
1049
1050 scr->pcs.visibleoffset = scr->pcs.dispoffset = scr->mindispoffset;
1051 if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) {
1052 vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9);
1053 vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1);
1054 }
1055
1056 bus_space_write_region_2(vh->vh_memt, vh->vh_memh,
1057 scr->pcs.dispoffset, scr->pcs.mem, type->ncols * type->nrows);
1058 scr->pcs.active = 1;
1059
1060 vc->active = scr;
1061
1062 pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron,
1063 scr->pcs.cursorrow, scr->pcs.cursorcol);
1064
1065 vc->wantedscreen = 0;
1066 if (vc->switchcb)
1067 (*vc->switchcb)(vc->switchcbarg, 0, 0);
1068 }
1069
1070 static int
vga_load_font(void * v,void * cookie,struct wsdisplay_font * data)1071 vga_load_font(void *v, void *cookie, struct wsdisplay_font *data)
1072 {
1073 struct vga_config *vc = v;
1074 struct vgascreen *scr = cookie;
1075 char *name2;
1076 int res;
1077
1078 if (scr) {
1079 name2 = NULL;
1080 if (data->name) {
1081 name2 = strchr(data->name, ',');
1082 if (name2)
1083 *name2++ = '\0';
1084 }
1085 res = vga_selectfont(vc, scr, data->name, name2);
1086 if (!res && scr->pcs.active)
1087 vga_setfont(vc, scr);
1088 return (res);
1089 }
1090
1091 return (0);
1092 }
1093
1094 static int
vga_allocattr(void * id,int fg,int bg,int flags,long * attrp)1095 vga_allocattr(void *id, int fg, int bg, int flags, long *attrp)
1096 {
1097 struct vgascreen *scr = id;
1098 struct vga_config *vc = scr->cfg;
1099
1100 if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) ||
1101 (unsigned int)bg >= sizeof(bgansitopc)))
1102 return (EINVAL);
1103
1104 if (vc->hdl.vh_mono) {
1105 if (flags & WSATTR_WSCOLORS)
1106 return (EINVAL);
1107 if (flags & WSATTR_REVERSE)
1108 *attrp = 0x70;
1109 else
1110 *attrp = 0x07;
1111 if (flags & WSATTR_UNDERLINE)
1112 *attrp |= FG_UNDERLINE;
1113 if (flags & WSATTR_HILIT)
1114 *attrp |= FG_INTENSE;
1115 } else {
1116 if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE))
1117 return (EINVAL);
1118 if (flags & WSATTR_WSCOLORS)
1119 *attrp = fgansitopc[fg] | bgansitopc[bg];
1120 else
1121 *attrp = 7;
1122 if (flags & WSATTR_HILIT)
1123 *attrp += 8;
1124 }
1125 if (flags & WSATTR_BLINK)
1126 *attrp |= FG_BLINK;
1127 return (0);
1128 }
1129
1130 static void
vga_copyrows(void * id,int srcrow,int dstrow,int nrows)1131 vga_copyrows(void *id, int srcrow, int dstrow, int nrows)
1132 {
1133 struct vgascreen *scr = id;
1134 bus_space_tag_t memt = scr->pcs.hdl->ph_memt;
1135 bus_space_handle_t memh = scr->pcs.hdl->ph_memh;
1136 int ncols = scr->pcs.type->ncols;
1137 bus_size_t srcoff, dstoff;
1138
1139 srcoff = srcrow * ncols + 0;
1140 dstoff = dstrow * ncols + 0;
1141
1142 if (scr->pcs.active) {
1143 if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) {
1144 #ifdef PCDISPLAY_SOFTCURSOR
1145 int cursoron = scr->pcs.cursoron;
1146
1147 if (cursoron)
1148 pcdisplay_cursor(&scr->pcs, 0,
1149 scr->pcs.cursorrow, scr->pcs.cursorcol);
1150 #endif
1151 /* scroll up whole screen */
1152 if ((scr->pcs.dispoffset + srcrow * ncols * 2)
1153 <= scr->maxdispoffset) {
1154 scr->pcs.dispoffset += srcrow * ncols * 2;
1155 } else {
1156 bus_space_copy_region_2(memt, memh,
1157 scr->pcs.dispoffset + srcoff * 2,
1158 memh, scr->mindispoffset, nrows * ncols);
1159 scr->pcs.dispoffset = scr->mindispoffset;
1160 }
1161 vga_6845_write(&scr->cfg->hdl, startadrh,
1162 scr->pcs.dispoffset >> 9);
1163 vga_6845_write(&scr->cfg->hdl, startadrl,
1164 scr->pcs.dispoffset >> 1);
1165 #ifdef PCDISPLAY_SOFTCURSOR
1166 if (cursoron)
1167 pcdisplay_cursor(&scr->pcs, 1,
1168 scr->pcs.cursorrow, scr->pcs.cursorcol);
1169 #endif
1170 } else {
1171 bus_space_copy_region_2(memt, memh,
1172 scr->pcs.dispoffset + srcoff * 2,
1173 memh, scr->pcs.dispoffset + dstoff * 2,
1174 nrows * ncols);
1175 }
1176 } else
1177 memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff],
1178 nrows * ncols * 2);
1179 }
1180
1181 #ifdef WSCONS_SUPPORT_PCVTFONTS
1182
1183 #define NOTYET 0xffff
1184 static const uint16_t pcvt_unichars[0xa0] = {
1185 /* 0 */ _e006U, /* N/L control */
1186 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1187 NOTYET,
1188 0x2409, /* SYMBOL FOR HORIZONTAL TABULATION */
1189 0x240a, /* SYMBOL FOR LINE FEED */
1190 0x240b, /* SYMBOL FOR VERTICAL TABULATION */
1191 0x240c, /* SYMBOL FOR FORM FEED */
1192 0x240d, /* SYMBOL FOR CARRIAGE RETURN */
1193 NOTYET, NOTYET,
1194 /* 1 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1195 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1196 /* 2 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1197 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1198 /* 3 */ NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1199 NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET, NOTYET,
1200 /* 4 */ 0x03c1, /* GREEK SMALL LETTER RHO */
1201 0x03c8, /* GREEK SMALL LETTER PSI */
1202 0x2202, /* PARTIAL DIFFERENTIAL */
1203 0x03bb, /* GREEK SMALL LETTER LAMDA */
1204 0x03b9, /* GREEK SMALL LETTER IOTA */
1205 0x03b7, /* GREEK SMALL LETTER ETA */
1206 0x03b5, /* GREEK SMALL LETTER EPSILON */
1207 0x03c7, /* GREEK SMALL LETTER CHI */
1208 0x2228, /* LOGICAL OR */
1209 0x2227, /* LOGICAL AND */
1210 0x222a, /* UNION */
1211 0x2283, /* SUPERSET OF */
1212 0x2282, /* SUBSET OF */
1213 0x03a5, /* GREEK CAPITAL LETTER UPSILON */
1214 0x039e, /* GREEK CAPITAL LETTER XI */
1215 0x03a8, /* GREEK CAPITAL LETTER PSI */
1216 /* 5 */ 0x03a0, /* GREEK CAPITAL LETTER PI */
1217 0x21d2, /* RIGHTWARDS DOUBLE ARROW */
1218 0x21d4, /* LEFT RIGHT DOUBLE ARROW */
1219 0x039b, /* GREEK CAPITAL LETTER LAMDA */
1220 0x0398, /* GREEK CAPITAL LETTER THETA */
1221 0x2243, /* ASYMPTOTICALLY EQUAL TO */
1222 0x2207, /* NABLA */
1223 0x2206, /* INCREMENT */
1224 0x221d, /* PROPORTIONAL TO */
1225 0x2234, /* THEREFORE */
1226 0x222b, /* INTEGRAL */
1227 0x2215, /* DIVISION SLASH */
1228 0x2216, /* SET MINUS */
1229 _e00eU, /* angle? */
1230 _e00dU, /* inverted angle? */
1231 _e00bU, /* braceleftmid */
1232 /* 6 */ _e00cU, /* bracerightmid */
1233 _e007U, /* bracelefttp */
1234 _e008U, /* braceleftbt */
1235 _e009U, /* bracerighttp */
1236 _e00aU, /* bracerightbt */
1237 0x221a, /* SQUARE ROOT */
1238 0x03c9, /* GREEK SMALL LETTER OMEGA */
1239 0x00a5, /* YEN SIGN */
1240 0x03be, /* GREEK SMALL LETTER XI */
1241 0x00fd, /* LATIN SMALL LETTER Y WITH ACUTE */
1242 0x00fe, /* LATIN SMALL LETTER THORN */
1243 0x00f0, /* LATIN SMALL LETTER ETH */
1244 0x00de, /* LATIN CAPITAL LETTER THORN */
1245 0x00dd, /* LATIN CAPITAL LETTER Y WITH ACUTE */
1246 0x00d7, /* MULTIPLICATION SIGN */
1247 0x00d0, /* LATIN CAPITAL LETTER ETH */
1248 /* 7 */ 0x00be, /* VULGAR FRACTION THREE QUARTERS */
1249 0x00b8, /* CEDILLA */
1250 0x00b4, /* ACUTE ACCENT */
1251 0x00af, /* MACRON */
1252 0x00ae, /* REGISTERED SIGN */
1253 0x00ad, /* SOFT HYPHEN */
1254 0x00ac, /* NOT SIGN */
1255 0x00a8, /* DIAERESIS */
1256 0x2260, /* NOT EQUAL TO */
1257 0x23bd, /* scan 9 */
1258 0x23bc, /* scan 7 */
1259 0x2500, /* scan 5 */
1260 0x23bb, /* scan 3 */
1261 0x23ba, /* scan 1 */
1262 0x03c5, /* GREEK SMALL LETTER UPSILON */
1263 0x00f8, /* LATIN SMALL LETTER O WITH STROKE */
1264 /* 8 */ 0x0153, /* LATIN SMALL LIGATURE OE */
1265 0x00f5, /* LATIN SMALL LETTER O WITH TILDE !!!doc bug */
1266 0x00e3, /* LATIN SMALL LETTER A WITH TILDE */
1267 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1268 0x00db, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1269 0x00da, /* LATIN CAPITAL LETTER U WITH ACUTE */
1270 0x00d9, /* LATIN CAPITAL LETTER U WITH GRAVE */
1271 0x00d8, /* LATIN CAPITAL LETTER O WITH STROKE */
1272 0x0152, /* LATIN CAPITAL LIGATURE OE */
1273 0x00d5, /* LATIN CAPITAL LETTER O WITH TILDE */
1274 0x00d4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1275 0x00d3, /* LATIN CAPITAL LETTER O WITH ACUTE */
1276 0x00d2, /* LATIN CAPITAL LETTER O WITH GRAVE */
1277 0x00cf, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1278 0x00ce, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1279 0x00cd, /* LATIN CAPITAL LETTER I WITH ACUTE */
1280 /* 9 */ 0x00cc, /* LATIN CAPITAL LETTER I WITH GRAVE */
1281 0x00cb, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1282 0x00ca, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1283 0x00c8, /* LATIN CAPITAL LETTER E WITH GRAVE */
1284 0x00c3, /* LATIN CAPITAL LETTER A WITH TILDE */
1285 0x00c2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1286 0x00c1, /* LATIN CAPITAL LETTER A WITH ACUTE */
1287 0x00c0, /* LATIN CAPITAL LETTER A WITH GRAVE */
1288 0x00b9, /* SUPERSCRIPT ONE */
1289 0x00b7, /* MIDDLE DOT */
1290 0x03b6, /* GREEK SMALL LETTER ZETA */
1291 0x00b3, /* SUPERSCRIPT THREE */
1292 0x00a9, /* COPYRIGHT SIGN */
1293 0x00a4, /* CURRENCY SIGN */
1294 0x03ba, /* GREEK SMALL LETTER KAPPA */
1295 _e000U /* mirrored question mark? */
1296 };
1297
1298 static int vga_pcvt_mapchar(int, u_int *);
1299
1300 static int
vga_pcvt_mapchar(int uni,u_int * index)1301 vga_pcvt_mapchar(int uni, u_int *index)
1302 {
1303 int i;
1304
1305 for (i = 0; i < 0xa0; i++) /* 0xa0..0xff are reserved */
1306 if (uni == pcvt_unichars[i]) {
1307 *index = i;
1308 return (5);
1309 }
1310 *index = 0x99; /* middle dot */
1311 return (0);
1312 }
1313
1314 #endif /* WSCONS_SUPPORT_PCVTFONTS */
1315
1316 #ifdef WSCONS_SUPPORT_ISO7FONTS
1317
1318 static int
vga_iso7_mapchar(int uni,u_int * index)1319 vga_iso7_mapchar(int uni, u_int *index)
1320 {
1321
1322 /*
1323 * U+0384 (GREEK TONOS) to
1324 * U+03ce (GREEK SMALL LETTER OMEGA WITH TONOS)
1325 * map directly to the iso-9 font
1326 */
1327 if (uni >= 0x0384 && uni <= 0x03ce) {
1328 /* U+0384 is at offset 0xb4 in the font */
1329 *index = uni - 0x0384 + 0xb4;
1330 return (5);
1331 }
1332
1333 /* XXX more chars in the iso-9 font */
1334
1335 *index = 0xa4; /* shaded rectangle */
1336 return (0);
1337 }
1338
1339 #endif /* WSCONS_SUPPORT_ISO7FONTS */
1340
1341 static const uint16_t iso2_unichars[0x60] = {
1342 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
1343 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
1344 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
1345 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
1346 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
1347 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
1348 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
1349 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
1350 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
1351 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
1352 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
1353 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
1354 };
1355
1356 static const uint16_t koi8_unichars[0x40] = {
1357 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
1358 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
1359 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
1360 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
1361 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
1362 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
1363 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
1364 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A
1365 };
1366
1367 static int _vga_mapchar(void *, const struct egavga_font *, int, u_int *);
1368
1369 static int
_vga_mapchar(void * id,const struct egavga_font * font,int uni,u_int * index)1370 _vga_mapchar(void *id, const struct egavga_font *font, int uni, u_int *index)
1371 {
1372
1373 switch (font->wsfont->encoding) {
1374 case WSDISPLAY_FONTENC_ISO:
1375 if (uni < 256) {
1376 *index = uni;
1377 return (5);
1378 } else {
1379 *index = ' ';
1380 return (0);
1381 }
1382 case WSDISPLAY_FONTENC_ISO2:
1383 if (uni < 0xa0) {
1384 *index = uni;
1385 return (5);
1386 } else {
1387 int i;
1388 for (i = 0; i < 0x60; i++) {
1389 if (uni == iso2_unichars[i]) {
1390 *index = i + 0xa0;
1391 return (5);
1392 }
1393 }
1394 *index = 0xa4; /* currency sign */
1395 return (0);
1396 }
1397 case WSDISPLAY_FONTENC_KOI8_R:
1398 if (uni < 0x80) {
1399 *index = uni;
1400 return (5);
1401 } else {
1402 int i;
1403 for (i = 0; i < 0x40; i++) {
1404 if (uni == koi8_unichars[i]) {
1405 *index = i + 0xc0;
1406 return (5);
1407 }
1408 }
1409 *index = 0x94; /* box */
1410 return (0);
1411 }
1412 case WSDISPLAY_FONTENC_IBM:
1413 return (pcdisplay_mapchar(id, uni, index));
1414 #ifdef WSCONS_SUPPORT_PCVTFONTS
1415 case WSDISPLAY_FONTENC_PCVT:
1416 return (vga_pcvt_mapchar(uni, index));
1417 #endif
1418 #ifdef WSCONS_SUPPORT_ISO7FONTS
1419 case WSDISPLAY_FONTENC_ISO7:
1420 return (vga_iso7_mapchar(uni, index));
1421 #endif
1422 default:
1423 #ifdef VGAFONTDEBUG
1424 printf("_vga_mapchar: encoding=%d\n", font->wsfont->encoding);
1425 #endif
1426 *index = ' ';
1427 return (0);
1428 }
1429 }
1430
1431 static int
vga_mapchar(void * id,int uni,u_int * index)1432 vga_mapchar(void *id, int uni, u_int *index)
1433 {
1434 struct vgascreen *scr = id;
1435 u_int idx1, idx2;
1436 int res1, res2;
1437
1438 res1 = 0;
1439 idx1 = ' '; /* space */
1440 if (scr->fontset1)
1441 res1 = _vga_mapchar(id, scr->fontset1, uni, &idx1);
1442 res2 = -1;
1443 if (scr->fontset2) {
1444 KASSERT(VGA_SCREEN_CANTWOFONTS(scr->pcs.type));
1445 res2 = _vga_mapchar(id, scr->fontset2, uni, &idx2);
1446 }
1447 if (res2 > res1) {
1448 *index = idx2 | 0x0800; /* attribute bit 3 */
1449 return (res2);
1450 }
1451 *index = idx1;
1452 return (res1);
1453 }
1454
1455 #ifdef WSDISPLAY_SCROLLSUPPORT
1456 static void
vga_scroll(void * v,void * cookie,int lines)1457 vga_scroll(void *v, void *cookie, int lines)
1458 {
1459 struct vga_config *vc = v;
1460 struct vgascreen *scr = cookie;
1461 struct vga_handle *vh = &vc->hdl;
1462
1463 if (lines == 0) {
1464 if (scr->pcs.visibleoffset == scr->pcs.dispoffset)
1465 return;
1466
1467 scr->pcs.visibleoffset = scr->pcs.dispoffset;
1468 }
1469 else {
1470 int vga_scr_end;
1471 int margin = scr->pcs.type->ncols * 2;
1472 int ul, we, p, st;
1473
1474 vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols *
1475 scr->pcs.type->nrows * 2);
1476 if (scr->vga_rollover > vga_scr_end + margin) {
1477 ul = vga_scr_end;
1478 we = scr->vga_rollover + scr->pcs.type->ncols * 2;
1479 } else {
1480 ul = 0;
1481 we = 0x8000;
1482 }
1483 p = (scr->pcs.visibleoffset - ul + we) % we + lines *
1484 (scr->pcs.type->ncols * 2);
1485 st = (scr->pcs.dispoffset - ul + we) % we;
1486 if (p < margin)
1487 p = 0;
1488 if (p > st - margin)
1489 p = st;
1490 scr->pcs.visibleoffset = (p + ul) % we;
1491 }
1492
1493 vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9);
1494 vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1);
1495 }
1496 #endif
1497
1498 static void
vga_putchar(void * c,int row,int col,u_int uc,long attr)1499 vga_putchar(void *c, int row, int col, u_int uc, long attr)
1500 {
1501
1502 pcdisplay_putchar(c, row, col, uc, attr);
1503 }
1504
1505 #ifdef WSDISPLAY_CUSTOM_BORDER
1506 static int
vga_getborder(struct vga_config * vc,u_int * valuep)1507 vga_getborder(struct vga_config *vc, u_int *valuep)
1508 {
1509 struct vga_handle *vh = &vc->hdl;
1510 u_int idx;
1511 uint8_t value;
1512
1513 if (vh->vh_mono)
1514 return ENODEV;
1515
1516 value = _vga_attr_read(vh, VGA_ATC_OVERSCAN);
1517 for (idx = 0; idx < sizeof(fgansitopc); idx++) {
1518 if (fgansitopc[idx] == value) {
1519 *valuep = idx;
1520 return (0);
1521 }
1522 }
1523 return (EIO);
1524 }
1525
1526 static int
vga_setborder(struct vga_config * vc,u_int value)1527 vga_setborder(struct vga_config *vc, u_int value)
1528 {
1529 struct vga_handle *vh = &vc->hdl;
1530
1531 if (vh->vh_mono)
1532 return ENODEV;
1533 if (value >= sizeof(fgansitopc))
1534 return EINVAL;
1535
1536 _vga_attr_write(vh, VGA_ATC_OVERSCAN, fgansitopc[value]);
1537 return (0);
1538 }
1539 #endif /* WSDISPLAY_CUSTOM_BORDER */
1540
1541 void
vga_resume(struct vga_softc * sc)1542 vga_resume(struct vga_softc *sc)
1543 {
1544 #ifdef VGA_RESET_ON_RESUME
1545 vga_initregs(&sc->sc_vc->hdl);
1546 #endif
1547 #ifdef PCDISPLAY_SOFTCURSOR
1548 /* Disable the hardware cursor */
1549 vga_6845_write(&sc->sc_vc->hdl, curstart, 0x20);
1550 vga_6845_write(&sc->sc_vc->hdl, curend, 0x00);
1551 #endif
1552 }
1553
1554 static void
vga_save_palette(struct vga_config * vc)1555 vga_save_palette(struct vga_config *vc)
1556 {
1557 struct vga_handle *vh = &vc->hdl;
1558 size_t i;
1559 uint8_t *palette = vc->palette;
1560
1561 if (vh->vh_mono)
1562 return;
1563
1564 vga_raw_write(vh, VGA_DAC_PELMASK, 0xff);
1565 vga_raw_write(vh, VGA_DAC_ADDRR, 0x00);
1566 for (i = 0; i < sizeof(vc->palette); i++)
1567 *palette++ = vga_raw_read(vh, VGA_DAC_PALETTE);
1568
1569 vga_reset_state(vh); /* reset flip/flop */
1570 }
1571
1572 static void
vga_restore_palette(struct vga_config * vc)1573 vga_restore_palette(struct vga_config *vc)
1574 {
1575 struct vga_handle *vh = &vc->hdl;
1576 size_t i;
1577 uint8_t *palette = vc->palette;
1578
1579 if (vh->vh_mono)
1580 return;
1581
1582 vga_raw_write(vh, VGA_DAC_PELMASK, 0xff);
1583 vga_raw_write(vh, VGA_DAC_ADDRW, 0x00);
1584 for (i = 0; i < sizeof(vc->palette); i++)
1585 vga_raw_write(vh, VGA_DAC_PALETTE, *palette++);
1586
1587 vga_reset_state(vh); /* reset flip/flop */
1588 vga_enable(vh);
1589 }
1590