1 1.33 andvar /* $NetBSD: ega.c,v 1.33 2025/07/14 06:15:55 andvar Exp $ */ 2 1.1 drochner 3 1.1 drochner /* 4 1.1 drochner * Copyright (c) 1999 5 1.1 drochner * Matthias Drochner. All rights reserved. 6 1.1 drochner * 7 1.1 drochner * Redistribution and use in source and binary forms, with or without 8 1.1 drochner * modification, are permitted provided that the following conditions 9 1.1 drochner * are met: 10 1.1 drochner * 1. Redistributions of source code must retain the above copyright 11 1.1 drochner * notice, this list of conditions and the following disclaimer. 12 1.1 drochner * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 drochner * notice, this list of conditions and the following disclaimer in the 14 1.1 drochner * documentation and/or other materials provided with the distribution. 15 1.1 drochner * 16 1.1 drochner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 drochner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 drochner * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 drochner * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 drochner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 drochner * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 drochner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 drochner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 drochner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.1 drochner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 drochner * 27 1.1 drochner */ 28 1.7 lukem 29 1.7 lukem #include <sys/cdefs.h> 30 1.33 andvar __KERNEL_RCSID(0, "$NetBSD: ega.c,v 1.33 2025/07/14 06:15:55 andvar Exp $"); 31 1.1 drochner 32 1.1 drochner #include <sys/param.h> 33 1.1 drochner #include <sys/systm.h> 34 1.4 thorpej #include <sys/callout.h> 35 1.1 drochner #include <sys/kernel.h> 36 1.1 drochner #include <sys/device.h> 37 1.1 drochner #include <sys/malloc.h> 38 1.24 ad #include <sys/bus.h> 39 1.1 drochner 40 1.1 drochner #include <dev/isa/isavar.h> 41 1.1 drochner 42 1.1 drochner #include <dev/ic/mc6845reg.h> 43 1.1 drochner #include <dev/ic/pcdisplayvar.h> 44 1.1 drochner #include <dev/ic/vgareg.h> 45 1.1 drochner #include <dev/ic/vgavar.h> 46 1.1 drochner #include <dev/isa/egavar.h> 47 1.1 drochner 48 1.1 drochner #include <dev/ic/pcdisplay.h> 49 1.1 drochner 50 1.1 drochner #include <dev/wscons/wsconsio.h> 51 1.1 drochner #include <dev/wscons/wsdisplayvar.h> 52 1.1 drochner 53 1.1 drochner static struct egafont { 54 1.1 drochner char name[16]; 55 1.1 drochner int height; 56 1.1 drochner int encoding; 57 1.1 drochner int slot; 58 1.1 drochner } ega_builtinfont = { 59 1.1 drochner "builtin", 60 1.1 drochner 14, 61 1.1 drochner WSDISPLAY_FONTENC_IBM, 62 1.1 drochner 0 63 1.1 drochner }; 64 1.1 drochner 65 1.1 drochner struct egascreen { 66 1.1 drochner struct pcdisplayscreen pcs; 67 1.1 drochner LIST_ENTRY(egascreen) next; 68 1.1 drochner struct ega_config *cfg; 69 1.1 drochner struct egafont *fontset1, *fontset2; 70 1.1 drochner 71 1.1 drochner int mindispoffset, maxdispoffset; 72 1.1 drochner }; 73 1.1 drochner 74 1.1 drochner struct ega_config { 75 1.1 drochner struct vga_handle hdl; 76 1.1 drochner 77 1.1 drochner int nscreens; 78 1.1 drochner LIST_HEAD(, egascreen) screens; 79 1.1 drochner struct egascreen *active; /* current display */ 80 1.1 drochner const struct wsscreen_descr *currenttype; 81 1.1 drochner int currentfontset1, currentfontset2; 82 1.1 drochner 83 1.1 drochner struct egafont *vc_fonts[4]; 84 1.1 drochner 85 1.1 drochner struct egascreen *wantedscreen; 86 1.12 junyoung void (*switchcb)(void *, int, int); 87 1.1 drochner void *switchcbarg; 88 1.4 thorpej 89 1.22 ad callout_t switch_callout; 90 1.1 drochner }; 91 1.1 drochner 92 1.1 drochner struct ega_softc { 93 1.1 drochner struct ega_config *sc_dc; 94 1.1 drochner int nscreens; 95 1.1 drochner }; 96 1.1 drochner 97 1.1 drochner static int egaconsole, ega_console_attached; 98 1.1 drochner static struct egascreen ega_console_screen; 99 1.1 drochner static struct ega_config ega_console_dc; 100 1.1 drochner 101 1.29 cegger int ega_match(device_t, cfdata_t, void *); 102 1.29 cegger void ega_attach(device_t, device_t, void *); 103 1.1 drochner 104 1.12 junyoung static int ega_is_console(bus_space_tag_t); 105 1.12 junyoung static int ega_probe_col(bus_space_tag_t, bus_space_tag_t); 106 1.12 junyoung static int ega_probe_mono(bus_space_tag_t, bus_space_tag_t); 107 1.12 junyoung int ega_selectfont(struct ega_config *, struct egascreen *, char *, char *); 108 1.12 junyoung void ega_init_screen(struct ega_config *, struct egascreen *, 109 1.12 junyoung const struct wsscreen_descr *, int, long *); 110 1.18 perry static void ega_init(struct ega_config *, bus_space_tag_t, bus_space_tag_t, 111 1.12 junyoung int); 112 1.12 junyoung static void ega_setfont(struct ega_config *, struct egascreen *); 113 1.12 junyoung static int ega_allocattr(void *, int, int, int, long *); 114 1.12 junyoung void ega_copyrows(void *, int, int, int); 115 1.1 drochner 116 1.30 chs CFATTACH_DECL_NEW(ega, sizeof(struct ega_softc), 117 1.15 thorpej ega_match, ega_attach, NULL, NULL); 118 1.1 drochner 119 1.1 drochner const struct wsdisplay_emulops ega_emulops = { 120 1.1 drochner pcdisplay_cursor, 121 1.1 drochner pcdisplay_mapchar, 122 1.1 drochner pcdisplay_putchar, 123 1.1 drochner pcdisplay_copycols, 124 1.1 drochner pcdisplay_erasecols, 125 1.1 drochner ega_copyrows, 126 1.1 drochner pcdisplay_eraserows, 127 1.10 junyoung ega_allocattr 128 1.1 drochner }; 129 1.1 drochner 130 1.1 drochner /* 131 1.1 drochner * translate WS(=ANSI) color codes to standard pc ones 132 1.1 drochner */ 133 1.1 drochner static unsigned char fgansitopc[] = { 134 1.1 drochner FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE, 135 1.1 drochner FG_MAGENTA, FG_CYAN, FG_LIGHTGREY 136 1.1 drochner }, bgansitopc[] = { 137 1.1 drochner BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE, 138 1.1 drochner BG_MAGENTA, BG_CYAN, BG_LIGHTGREY 139 1.1 drochner }; 140 1.1 drochner 141 1.1 drochner const struct wsscreen_descr ega_stdscreen = { 142 1.1 drochner "80x25", 80, 25, 143 1.1 drochner &ega_emulops, 144 1.1 drochner 8, 14, 145 1.1 drochner WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 146 1.1 drochner }, ega_stdscreen_mono = { 147 1.1 drochner "80x25", 80, 25, 148 1.1 drochner &ega_emulops, 149 1.1 drochner 8, 14, 150 1.1 drochner WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 151 1.1 drochner }, ega_stdscreen_bf = { 152 1.1 drochner "80x25bf", 80, 25, 153 1.1 drochner &ega_emulops, 154 1.1 drochner 8, 14, 155 1.1 drochner WSSCREEN_WSCOLORS | WSSCREEN_BLINK 156 1.1 drochner }, ega_35lscreen = { 157 1.1 drochner "80x35", 80, 35, 158 1.1 drochner &ega_emulops, 159 1.1 drochner 8, 10, 160 1.1 drochner WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 161 1.1 drochner }, ega_35lscreen_mono = { 162 1.1 drochner "80x35", 80, 35, 163 1.1 drochner &ega_emulops, 164 1.1 drochner 8, 10, 165 1.1 drochner WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 166 1.1 drochner }, ega_35lscreen_bf = { 167 1.1 drochner "80x35bf", 80, 35, 168 1.1 drochner &ega_emulops, 169 1.1 drochner 8, 10, 170 1.1 drochner WSSCREEN_WSCOLORS | WSSCREEN_BLINK 171 1.1 drochner }, ega_43lscreen = { 172 1.1 drochner "80x43", 80, 43, 173 1.1 drochner &ega_emulops, 174 1.1 drochner 8, 8, 175 1.1 drochner WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_BLINK 176 1.1 drochner }, ega_43lscreen_mono = { 177 1.1 drochner "80x43", 80, 43, 178 1.1 drochner &ega_emulops, 179 1.1 drochner 8, 8, 180 1.1 drochner WSSCREEN_HILIT | WSSCREEN_UNDERLINE | WSSCREEN_BLINK | WSSCREEN_REVERSE 181 1.1 drochner }, ega_43lscreen_bf = { 182 1.1 drochner "80x43bf", 80, 43, 183 1.1 drochner &ega_emulops, 184 1.1 drochner 8, 8, 185 1.1 drochner WSSCREEN_WSCOLORS | WSSCREEN_BLINK 186 1.1 drochner }; 187 1.1 drochner 188 1.1 drochner #define VGA_SCREEN_CANTWOFONTS(type) (!((type)->capabilities & WSSCREEN_HILIT)) 189 1.1 drochner 190 1.1 drochner const struct wsscreen_descr *_ega_scrlist[] = { 191 1.1 drochner &ega_stdscreen, 192 1.1 drochner &ega_stdscreen_bf, 193 1.1 drochner &ega_35lscreen, 194 1.1 drochner &ega_35lscreen_bf, 195 1.1 drochner &ega_43lscreen, 196 1.1 drochner &ega_43lscreen_bf, 197 1.1 drochner }, *_ega_scrlist_mono[] = { 198 1.1 drochner &ega_stdscreen_mono, 199 1.1 drochner &ega_35lscreen_mono, 200 1.1 drochner &ega_43lscreen_mono, 201 1.1 drochner }; 202 1.1 drochner 203 1.1 drochner 204 1.1 drochner const struct wsscreen_list ega_screenlist = { 205 1.1 drochner sizeof(_ega_scrlist) / sizeof(struct wsscreen_descr *), 206 1.1 drochner _ega_scrlist 207 1.1 drochner }, ega_screenlist_mono = { 208 1.1 drochner sizeof(_ega_scrlist_mono) / sizeof(struct wsscreen_descr *), 209 1.1 drochner _ega_scrlist_mono 210 1.1 drochner }; 211 1.1 drochner 212 1.21 christos static int ega_ioctl(void *, void *, u_long, void *, int, struct proc *); 213 1.20 jmmv static paddr_t ega_mmap(void *, void *, off_t, int); 214 1.12 junyoung static int ega_alloc_screen(void *, const struct wsscreen_descr *, 215 1.12 junyoung void **, int *, int *, long *); 216 1.12 junyoung static void ega_free_screen(void *, void *); 217 1.12 junyoung static int ega_show_screen(void *, void *, int, 218 1.12 junyoung void (*) (void *, int, int), void *); 219 1.12 junyoung static int ega_load_font(void *, void *, struct wsdisplay_font *); 220 1.1 drochner 221 1.12 junyoung void ega_doswitch(struct ega_config *); 222 1.1 drochner 223 1.1 drochner const struct wsdisplay_accessops ega_accessops = { 224 1.1 drochner ega_ioctl, 225 1.1 drochner ega_mmap, 226 1.1 drochner ega_alloc_screen, 227 1.1 drochner ega_free_screen, 228 1.1 drochner ega_show_screen, 229 1.1 drochner ega_load_font 230 1.1 drochner }; 231 1.1 drochner 232 1.1 drochner static int 233 1.26 dsl ega_probe_col(bus_space_tag_t iot, bus_space_tag_t memt) 234 1.1 drochner { 235 1.1 drochner bus_space_handle_t memh, ioh_6845; 236 1.1 drochner u_int16_t oldval, val; 237 1.1 drochner 238 1.1 drochner if (bus_space_map(memt, 0xb8000, 0x8000, 0, &memh)) 239 1.1 drochner return (0); 240 1.1 drochner oldval = bus_space_read_2(memt, memh, 0); 241 1.1 drochner bus_space_write_2(memt, memh, 0, 0xa55a); 242 1.1 drochner val = bus_space_read_2(memt, memh, 0); 243 1.1 drochner bus_space_write_2(memt, memh, 0, oldval); 244 1.1 drochner bus_space_unmap(memt, memh, 0x8000); 245 1.1 drochner if (val != 0xa55a) 246 1.1 drochner return (0); 247 1.1 drochner 248 1.1 drochner if (bus_space_map(iot, 0x3d0, 0x10, 0, &ioh_6845)) 249 1.1 drochner return (0); 250 1.1 drochner bus_space_unmap(iot, ioh_6845, 0x10); 251 1.1 drochner 252 1.1 drochner return (1); 253 1.1 drochner } 254 1.1 drochner 255 1.1 drochner static int 256 1.26 dsl ega_probe_mono(bus_space_tag_t iot, bus_space_tag_t memt) 257 1.1 drochner { 258 1.1 drochner bus_space_handle_t memh, ioh_6845; 259 1.1 drochner u_int16_t oldval, val; 260 1.1 drochner 261 1.1 drochner if (bus_space_map(memt, 0xb0000, 0x8000, 0, &memh)) 262 1.1 drochner return (0); 263 1.1 drochner oldval = bus_space_read_2(memt, memh, 0); 264 1.1 drochner bus_space_write_2(memt, memh, 0, 0xa55a); 265 1.1 drochner val = bus_space_read_2(memt, memh, 0); 266 1.1 drochner bus_space_write_2(memt, memh, 0, oldval); 267 1.1 drochner bus_space_unmap(memt, memh, 0x8000); 268 1.1 drochner if (val != 0xa55a) 269 1.1 drochner return (0); 270 1.1 drochner 271 1.1 drochner if (bus_space_map(iot, 0x3b0, 0x10, 0, &ioh_6845)) 272 1.1 drochner return (0); 273 1.1 drochner bus_space_unmap(iot, ioh_6845, 0x10); 274 1.1 drochner 275 1.1 drochner return (1); 276 1.1 drochner } 277 1.1 drochner /* 278 1.1 drochner * We want at least ASCII 32..127 be present in the 279 1.1 drochner * first font slot. 280 1.1 drochner */ 281 1.1 drochner #define vga_valid_primary_font(f) \ 282 1.1 drochner (f->encoding == WSDISPLAY_FONTENC_IBM || \ 283 1.1 drochner f->encoding == WSDISPLAY_FONTENC_ISO) 284 1.1 drochner 285 1.1 drochner int 286 1.26 dsl ega_selectfont(struct ega_config *vc, struct egascreen *scr, char *name1, char *name2) 287 1.26 dsl /* name1, *name2: NULL: take first found */ 288 1.1 drochner { 289 1.1 drochner const struct wsscreen_descr *type = scr->pcs.type; 290 1.1 drochner struct egafont *f1, *f2; 291 1.1 drochner int i; 292 1.1 drochner 293 1.1 drochner f1 = f2 = 0; 294 1.1 drochner 295 1.1 drochner for (i = 0; i < 4; i++) { 296 1.1 drochner struct egafont *f = vc->vc_fonts[i]; 297 1.1 drochner if (!f || f->height != type->fontheight) 298 1.1 drochner continue; 299 1.1 drochner if (!f1 && 300 1.1 drochner vga_valid_primary_font(f) && 301 1.1 drochner (!name1 || !strcmp(name1, f->name))) { 302 1.1 drochner f1 = f; 303 1.1 drochner continue; 304 1.1 drochner } 305 1.1 drochner if (!f2 && 306 1.1 drochner VGA_SCREEN_CANTWOFONTS(type) && 307 1.1 drochner (!name2 || !strcmp(name2, f->name))) { 308 1.1 drochner f2 = f; 309 1.1 drochner continue; 310 1.1 drochner } 311 1.1 drochner } 312 1.1 drochner 313 1.1 drochner /* 314 1.1 drochner * The request fails if no primary font was found, 315 1.1 drochner * or if a second font was requested but not found. 316 1.1 drochner */ 317 1.1 drochner if (f1 && (!name2 || f2)) { 318 1.1 drochner #ifdef EGAFONTDEBUG 319 1.1 drochner if (scr != &ega_console_screen || ega_console_attached) { 320 1.1 drochner printf("ega (%s): font1=%s (slot %d)", type->name, 321 1.1 drochner f1->name, f1->slot); 322 1.1 drochner if (f2) 323 1.1 drochner printf(", font2=%s (slot %d)", 324 1.1 drochner f2->name, f2->slot); 325 1.1 drochner printf("\n"); 326 1.1 drochner } 327 1.1 drochner #endif 328 1.1 drochner scr->fontset1 = f1; 329 1.1 drochner scr->fontset2 = f2; 330 1.1 drochner return (0); 331 1.1 drochner } 332 1.1 drochner return (ENXIO); 333 1.1 drochner } 334 1.1 drochner 335 1.1 drochner void 336 1.25 dsl ega_init_screen(struct ega_config *vc, struct egascreen *scr, const struct wsscreen_descr *type, int existing, long *attrp) 337 1.1 drochner { 338 1.1 drochner int cpos; 339 1.1 drochner int res; 340 1.1 drochner 341 1.1 drochner scr->cfg = vc; 342 1.1 drochner scr->pcs.hdl = (struct pcdisplay_handle *)&vc->hdl; 343 1.1 drochner scr->pcs.type = type; 344 1.1 drochner scr->pcs.active = 0; 345 1.1 drochner scr->mindispoffset = 0; 346 1.1 drochner scr->maxdispoffset = 0x8000 - type->nrows * type->ncols * 2; 347 1.1 drochner 348 1.1 drochner if (existing) { 349 1.1 drochner cpos = vga_6845_read(&vc->hdl, cursorh) << 8; 350 1.1 drochner cpos |= vga_6845_read(&vc->hdl, cursorl); 351 1.1 drochner 352 1.1 drochner /* make sure we have a valid cursor position */ 353 1.1 drochner if (cpos < 0 || cpos >= type->nrows * type->ncols) 354 1.1 drochner cpos = 0; 355 1.1 drochner 356 1.1 drochner scr->pcs.dispoffset = vga_6845_read(&vc->hdl, startadrh) << 9; 357 1.1 drochner scr->pcs.dispoffset |= vga_6845_read(&vc->hdl, startadrl) << 1; 358 1.1 drochner 359 1.1 drochner /* make sure we have a valid memory offset */ 360 1.1 drochner if (scr->pcs.dispoffset < scr->mindispoffset || 361 1.1 drochner scr->pcs.dispoffset > scr->maxdispoffset) 362 1.1 drochner scr->pcs.dispoffset = scr->mindispoffset; 363 1.1 drochner } else { 364 1.1 drochner cpos = 0; 365 1.1 drochner scr->pcs.dispoffset = scr->mindispoffset; 366 1.1 drochner } 367 1.1 drochner 368 1.11 junyoung scr->pcs.cursorrow = cpos / type->ncols; 369 1.11 junyoung scr->pcs.cursorcol = cpos % type->ncols; 370 1.3 ad pcdisplay_cursor_init(&scr->pcs, existing); 371 1.1 drochner 372 1.10 junyoung res = ega_allocattr(scr, 0, 0, 0, attrp); 373 1.1 drochner #ifdef DIAGNOSTIC 374 1.1 drochner if (res) 375 1.1 drochner panic("ega_init_screen: attribute botch"); 376 1.1 drochner #endif 377 1.1 drochner 378 1.1 drochner scr->pcs.mem = NULL; 379 1.1 drochner 380 1.1 drochner scr->fontset1 = scr->fontset2 = 0; 381 1.1 drochner if (ega_selectfont(vc, scr, 0, 0)) { 382 1.1 drochner if (scr == &ega_console_screen) 383 1.1 drochner panic("ega_init_screen: no font"); 384 1.1 drochner else 385 1.1 drochner printf("ega_init_screen: no font\n"); 386 1.1 drochner } 387 1.1 drochner 388 1.1 drochner vc->nscreens++; 389 1.1 drochner LIST_INSERT_HEAD(&vc->screens, scr, next); 390 1.1 drochner } 391 1.1 drochner 392 1.1 drochner static void 393 1.26 dsl ega_init(struct ega_config *vc, bus_space_tag_t iot, bus_space_tag_t memt, int mono) 394 1.1 drochner { 395 1.1 drochner struct vga_handle *vh = &vc->hdl; 396 1.1 drochner int i; 397 1.1 drochner 398 1.1 drochner vh->vh_iot = iot; 399 1.1 drochner vh->vh_memt = memt; 400 1.1 drochner vh->vh_mono = mono; 401 1.1 drochner 402 1.1 drochner if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga)) 403 1.1 drochner panic("ega_common_setup: couldn't map ega io"); 404 1.1 drochner 405 1.1 drochner if (bus_space_map(vh->vh_iot, (vh->vh_mono ? 0x3b0 : 0x3d0), 0x10, 0, 406 1.1 drochner &vh->vh_ioh_6845)) 407 1.1 drochner panic("ega_common_setup: couldn't map 6845 io"); 408 1.1 drochner 409 1.1 drochner if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh)) 410 1.1 drochner panic("ega_common_setup: couldn't map memory"); 411 1.1 drochner 412 1.1 drochner if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh, 413 1.1 drochner (vh->vh_mono ? 0x10000 : 0x18000), 0x8000, 414 1.1 drochner &vh->vh_memh)) 415 1.1 drochner panic("ega_common_setup: mem subrange failed"); 416 1.1 drochner 417 1.1 drochner vc->nscreens = 0; 418 1.1 drochner LIST_INIT(&vc->screens); 419 1.1 drochner vc->active = NULL; 420 1.1 drochner vc->currenttype = vh->vh_mono ? &ega_stdscreen_mono : &ega_stdscreen; 421 1.22 ad callout_init(&vc->switch_callout, 0); 422 1.1 drochner 423 1.1 drochner vc->vc_fonts[0] = &ega_builtinfont; 424 1.1 drochner for (i = 1; i < 4; i++) 425 1.1 drochner vc->vc_fonts[i] = 0; 426 1.1 drochner 427 1.1 drochner vc->currentfontset1 = vc->currentfontset2 = 0; 428 1.1 drochner } 429 1.1 drochner 430 1.1 drochner int 431 1.29 cegger ega_match(device_t parent, cfdata_t match, void *aux) 432 1.1 drochner { 433 1.1 drochner struct isa_attach_args *ia = aux; 434 1.1 drochner int mono; 435 1.1 drochner 436 1.8 christos if (ia->ia_nio < 1) 437 1.8 christos return (0); 438 1.8 christos 439 1.8 christos if (ia->ia_iomem < 1) 440 1.8 christos return (0); 441 1.8 christos 442 1.8 christos if (ia->ia_nirq < 1) 443 1.8 christos return (0); 444 1.8 christos 445 1.8 christos if (ia->ia_ndrq < 1) 446 1.8 christos return (0); 447 1.8 christos 448 1.8 christos if (ISA_DIRECT_CONFIG(ia)) 449 1.8 christos return (0); 450 1.8 christos 451 1.1 drochner /* If values are hardwired to something that they can't be, punt. */ 452 1.17 drochner if ((ia->ia_io[0].ir_addr != ISA_UNKNOWN_PORT && 453 1.8 christos ia->ia_io[0].ir_addr != 0x3d0 && 454 1.8 christos ia->ia_io[0].ir_addr != 0x3b0) || 455 1.8 christos /* ia->ia_io[0].ir_size != 0 || XXX isa.c */ 456 1.17 drochner (ia->ia_iomem[0].ir_addr != ISA_UNKNOWN_IOMEM && 457 1.8 christos ia->ia_iomem[0].ir_addr != 0xb8000 && 458 1.8 christos ia->ia_iomem[0].ir_addr != 0xb0000) || 459 1.8 christos (ia->ia_iomem[0].ir_size != 0 && 460 1.8 christos ia->ia_iomem[0].ir_size != 0x8000) || 461 1.17 drochner ia->ia_irq[0].ir_irq != ISA_UNKNOWN_IRQ || 462 1.17 drochner ia->ia_drq[0].ir_drq != ISA_UNKNOWN_DRQ) 463 1.1 drochner return (0); 464 1.1 drochner 465 1.1 drochner if (ega_is_console(ia->ia_iot)) 466 1.1 drochner mono = ega_console_dc.hdl.vh_mono; 467 1.8 christos else if (ia->ia_io[0].ir_addr != 0x3b0 && 468 1.8 christos ia->ia_iomem[0].ir_addr != 0xb0000 && 469 1.1 drochner ega_probe_col(ia->ia_iot, ia->ia_memt)) 470 1.1 drochner mono = 0; 471 1.8 christos else if (ia->ia_io[0].ir_addr != 0x3d0 && 472 1.8 christos ia->ia_iomem[0].ir_addr != 0xb8000 && 473 1.1 drochner ega_probe_mono(ia->ia_iot, ia->ia_memt)) 474 1.1 drochner mono = 1; 475 1.1 drochner else 476 1.1 drochner return (0); 477 1.1 drochner 478 1.8 christos ia->ia_io[0].ir_addr = mono ? 0x3b0 : 0x3d0; 479 1.8 christos ia->ia_io[0].ir_size = 0x10; 480 1.8 christos ia->ia_iomem[0].ir_addr = mono ? 0xb0000 : 0xb8000; 481 1.8 christos ia->ia_iomem[0].ir_size = 0x8000; 482 1.1 drochner return (2); /* beat pcdisplay */ 483 1.1 drochner } 484 1.1 drochner 485 1.1 drochner void 486 1.29 cegger ega_attach(device_t parent, device_t self, void *aux) 487 1.1 drochner { 488 1.1 drochner struct isa_attach_args *ia = aux; 489 1.30 chs struct ega_softc *sc = device_private(self); 490 1.1 drochner int console; 491 1.1 drochner struct ega_config *dc; 492 1.1 drochner struct wsemuldisplaydev_attach_args aa; 493 1.1 drochner 494 1.1 drochner printf("\n"); 495 1.1 drochner 496 1.1 drochner console = ega_is_console(ia->ia_iot); 497 1.1 drochner 498 1.1 drochner if (console) { 499 1.1 drochner dc = &ega_console_dc; 500 1.1 drochner sc->nscreens = 1; 501 1.1 drochner ega_console_attached = 1; 502 1.1 drochner } else { 503 1.1 drochner dc = malloc(sizeof(struct ega_config), 504 1.1 drochner M_DEVBUF, M_WAITOK); 505 1.8 christos if (ia->ia_io[0].ir_addr != 0x3b0 && 506 1.8 christos ia->ia_iomem[0].ir_addr != 0xb0000 && 507 1.1 drochner ega_probe_col(ia->ia_iot, ia->ia_memt)) 508 1.1 drochner ega_init(dc, ia->ia_iot, ia->ia_memt, 0); 509 1.8 christos else if (ia->ia_io[0].ir_addr != 0x3d0 && 510 1.8 christos ia->ia_iomem[0].ir_addr != 0xb8000 && 511 1.1 drochner ega_probe_mono(ia->ia_iot, ia->ia_memt)) 512 1.1 drochner ega_init(dc, ia->ia_iot, ia->ia_memt, 1); 513 1.1 drochner else 514 1.1 drochner panic("ega_attach: display disappeared"); 515 1.1 drochner } 516 1.1 drochner sc->sc_dc = dc; 517 1.1 drochner 518 1.1 drochner aa.console = console; 519 1.1 drochner aa.scrdata = &ega_screenlist; 520 1.1 drochner aa.accessops = &ega_accessops; 521 1.1 drochner aa.accesscookie = dc; 522 1.1 drochner 523 1.32 thorpej config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE); 524 1.1 drochner } 525 1.1 drochner 526 1.1 drochner 527 1.1 drochner int 528 1.26 dsl ega_cnattach(bus_space_tag_t iot, bus_space_tag_t memt) 529 1.1 drochner { 530 1.1 drochner int mono; 531 1.1 drochner long defattr; 532 1.1 drochner const struct wsscreen_descr *scr; 533 1.1 drochner 534 1.1 drochner if (ega_probe_col(iot, memt)) 535 1.1 drochner mono = 0; 536 1.1 drochner else if (ega_probe_mono(iot, memt)) 537 1.1 drochner mono = 1; 538 1.1 drochner else 539 1.1 drochner return (ENXIO); 540 1.1 drochner 541 1.1 drochner ega_init(&ega_console_dc, iot, memt, mono); 542 1.1 drochner scr = ega_console_dc.currenttype; 543 1.1 drochner ega_init_screen(&ega_console_dc, &ega_console_screen, scr, 1, &defattr); 544 1.1 drochner 545 1.1 drochner ega_console_screen.pcs.active = 1; 546 1.1 drochner ega_console_dc.active = &ega_console_screen; 547 1.1 drochner 548 1.1 drochner wsdisplay_cnattach(scr, &ega_console_screen, 549 1.11 junyoung ega_console_screen.pcs.cursorcol, 550 1.11 junyoung ega_console_screen.pcs.cursorrow, 551 1.1 drochner defattr); 552 1.1 drochner 553 1.1 drochner egaconsole = 1; 554 1.1 drochner return (0); 555 1.1 drochner } 556 1.1 drochner 557 1.1 drochner static int 558 1.25 dsl ega_is_console(bus_space_tag_t iot) 559 1.1 drochner { 560 1.1 drochner if (egaconsole && 561 1.1 drochner !ega_console_attached && 562 1.1 drochner iot == ega_console_dc.hdl.vh_iot) 563 1.1 drochner return (1); 564 1.1 drochner return (0); 565 1.1 drochner } 566 1.1 drochner 567 1.1 drochner static int 568 1.25 dsl ega_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct proc *p) 569 1.1 drochner { 570 1.1 drochner /* 571 1.1 drochner * XXX "do something!" 572 1.1 drochner */ 573 1.9 atatat return (EPASSTHROUGH); 574 1.1 drochner } 575 1.1 drochner 576 1.5 simonb static paddr_t 577 1.25 dsl ega_mmap(void *v, void *vs, off_t offset, int prot) 578 1.1 drochner { 579 1.1 drochner return (-1); 580 1.1 drochner } 581 1.1 drochner 582 1.1 drochner static int 583 1.26 dsl ega_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, int *curxp, int *curyp, long *defattrp) 584 1.1 drochner { 585 1.1 drochner struct ega_config *vc = v; 586 1.1 drochner struct egascreen *scr; 587 1.1 drochner 588 1.1 drochner if (vc->nscreens == 1) { 589 1.1 drochner /* 590 1.1 drochner * When allocating the second screen, get backing store 591 1.1 drochner * for the first one too. 592 1.1 drochner * XXX We could be more clever and use video RAM. 593 1.1 drochner */ 594 1.1 drochner vc->screens.lh_first->pcs.mem = 595 1.1 drochner malloc(type->ncols * type->nrows * 2, M_DEVBUF, M_WAITOK); 596 1.1 drochner } 597 1.1 drochner 598 1.1 drochner scr = malloc(sizeof(struct egascreen), M_DEVBUF, M_WAITOK); 599 1.1 drochner ega_init_screen(vc, scr, type, vc->nscreens == 0, defattrp); 600 1.1 drochner 601 1.1 drochner if (vc->nscreens == 1) { 602 1.1 drochner scr->pcs.active = 1; 603 1.1 drochner vc->active = scr; 604 1.1 drochner vc->currenttype = type; 605 1.1 drochner } else { 606 1.1 drochner scr->pcs.mem = malloc(type->ncols * type->nrows * 2, 607 1.1 drochner M_DEVBUF, M_WAITOK); 608 1.1 drochner pcdisplay_eraserows(&scr->pcs, 0, type->nrows, *defattrp); 609 1.1 drochner } 610 1.1 drochner 611 1.1 drochner *cookiep = scr; 612 1.11 junyoung *curxp = scr->pcs.cursorcol; 613 1.11 junyoung *curyp = scr->pcs.cursorrow; 614 1.1 drochner return (0); 615 1.1 drochner } 616 1.1 drochner 617 1.1 drochner static void 618 1.25 dsl ega_free_screen(void *v, void *cookie) 619 1.1 drochner { 620 1.1 drochner struct egascreen *vs = cookie; 621 1.1 drochner struct ega_config *vc = vs->cfg; 622 1.1 drochner 623 1.1 drochner LIST_REMOVE(vs, next); 624 1.1 drochner if (vs != &ega_console_screen) 625 1.1 drochner free(vs, M_DEVBUF); 626 1.1 drochner else 627 1.1 drochner panic("ega_free_screen: console"); 628 1.1 drochner 629 1.1 drochner if (vc->active == vs) 630 1.1 drochner vc->active = 0; 631 1.1 drochner } 632 1.1 drochner 633 1.1 drochner static void 634 1.25 dsl ega_setfont(struct ega_config *vc, struct egascreen *scr) 635 1.1 drochner { 636 1.1 drochner int fontslot1, fontslot2; 637 1.1 drochner 638 1.1 drochner fontslot1 = (scr->fontset1 ? scr->fontset1->slot : 0); 639 1.1 drochner fontslot2 = (scr->fontset2 ? scr->fontset2->slot : fontslot1); 640 1.1 drochner if (vc->currentfontset1 != fontslot1 || 641 1.1 drochner vc->currentfontset2 != fontslot2) { 642 1.1 drochner vga_setfontset(&vc->hdl, 2 * fontslot1, 2 * fontslot2); 643 1.1 drochner vc->currentfontset1 = fontslot1; 644 1.1 drochner vc->currentfontset2 = fontslot2; 645 1.1 drochner } 646 1.1 drochner } 647 1.1 drochner 648 1.1 drochner static int 649 1.27 dsl ega_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int), void *cbarg) 650 1.1 drochner { 651 1.1 drochner struct egascreen *scr = cookie, *oldscr; 652 1.1 drochner struct ega_config *vc = scr->cfg; 653 1.1 drochner 654 1.1 drochner oldscr = vc->active; /* can be NULL! */ 655 1.1 drochner if (scr == oldscr) { 656 1.1 drochner return (0); 657 1.1 drochner } 658 1.1 drochner 659 1.1 drochner vc->wantedscreen = cookie; 660 1.1 drochner vc->switchcb = cb; 661 1.1 drochner vc->switchcbarg = cbarg; 662 1.1 drochner if (cb) { 663 1.4 thorpej callout_reset(&vc->switch_callout, 0, 664 1.4 thorpej (void(*)(void *))ega_doswitch); 665 1.1 drochner return (EAGAIN); 666 1.1 drochner } 667 1.1 drochner 668 1.1 drochner ega_doswitch(vc); 669 1.1 drochner return (0); 670 1.1 drochner } 671 1.1 drochner 672 1.1 drochner void 673 1.25 dsl ega_doswitch(struct ega_config *vc) 674 1.1 drochner { 675 1.1 drochner struct egascreen *scr, *oldscr; 676 1.1 drochner struct vga_handle *vh = &vc->hdl; 677 1.1 drochner const struct wsscreen_descr *type; 678 1.1 drochner 679 1.1 drochner scr = vc->wantedscreen; 680 1.1 drochner if (!scr) { 681 1.1 drochner printf("ega_doswitch: disappeared\n"); 682 1.1 drochner (*vc->switchcb)(vc->switchcbarg, EIO, 0); 683 1.1 drochner return; 684 1.1 drochner } 685 1.1 drochner type = scr->pcs.type; 686 1.1 drochner oldscr = vc->active; /* can be NULL! */ 687 1.1 drochner #ifdef DIAGNOSTIC 688 1.1 drochner if (oldscr) { 689 1.1 drochner if (!oldscr->pcs.active) 690 1.1 drochner panic("ega_show_screen: not active"); 691 1.1 drochner if (oldscr->pcs.type != vc->currenttype) 692 1.1 drochner panic("ega_show_screen: bad type"); 693 1.1 drochner } 694 1.1 drochner #endif 695 1.1 drochner if (scr == oldscr) { 696 1.1 drochner return; 697 1.1 drochner } 698 1.1 drochner #ifdef DIAGNOSTIC 699 1.1 drochner if (scr->pcs.active) 700 1.1 drochner panic("ega_show_screen: active"); 701 1.1 drochner #endif 702 1.1 drochner 703 1.1 drochner if (oldscr) { 704 1.1 drochner const struct wsscreen_descr *oldtype = oldscr->pcs.type; 705 1.1 drochner 706 1.1 drochner oldscr->pcs.active = 0; 707 1.1 drochner bus_space_read_region_2(vh->vh_memt, vh->vh_memh, 708 1.1 drochner oldscr->pcs.dispoffset, oldscr->pcs.mem, 709 1.1 drochner oldtype->ncols * oldtype->nrows); 710 1.1 drochner } 711 1.1 drochner 712 1.1 drochner if (vc->currenttype != type) { 713 1.1 drochner vga_setscreentype(vh, type); 714 1.1 drochner vc->currenttype = type; 715 1.1 drochner } 716 1.1 drochner 717 1.1 drochner ega_setfont(vc, scr); 718 1.33 andvar /* XXX switch colours! */ 719 1.1 drochner 720 1.1 drochner scr->pcs.dispoffset = scr->mindispoffset; 721 1.1 drochner if (!oldscr || (scr->pcs.dispoffset != oldscr->pcs.dispoffset)) { 722 1.1 drochner vga_6845_write(vh, startadrh, scr->pcs.dispoffset >> 9); 723 1.1 drochner vga_6845_write(vh, startadrl, scr->pcs.dispoffset >> 1); 724 1.1 drochner } 725 1.1 drochner 726 1.1 drochner bus_space_write_region_2(vh->vh_memt, vh->vh_memh, 727 1.1 drochner scr->pcs.dispoffset, scr->pcs.mem, 728 1.1 drochner type->ncols * type->nrows); 729 1.1 drochner scr->pcs.active = 1; 730 1.1 drochner 731 1.1 drochner vc->active = scr; 732 1.1 drochner 733 1.1 drochner pcdisplay_cursor(&scr->pcs, scr->pcs.cursoron, 734 1.11 junyoung scr->pcs.cursorrow, scr->pcs.cursorcol); 735 1.1 drochner 736 1.1 drochner vc->wantedscreen = 0; 737 1.1 drochner if (vc->switchcb) 738 1.1 drochner (*vc->switchcb)(vc->switchcbarg, 0, 0); 739 1.1 drochner } 740 1.1 drochner 741 1.1 drochner static int 742 1.25 dsl ega_load_font(void *v, void *cookie, struct wsdisplay_font *data) 743 1.1 drochner { 744 1.1 drochner struct ega_config *vc = v; 745 1.1 drochner struct egascreen *scr = cookie; 746 1.1 drochner char *name2; 747 1.1 drochner int res, slot; 748 1.1 drochner struct egafont *f; 749 1.1 drochner 750 1.1 drochner if (scr) { 751 1.1 drochner name2 = strchr(data->name, ','); 752 1.1 drochner if (name2) 753 1.1 drochner *name2++ = '\0'; 754 1.1 drochner res = ega_selectfont(vc, scr, data->name, name2); 755 1.1 drochner if (!res) 756 1.1 drochner ega_setfont(vc, scr); 757 1.1 drochner return (res); 758 1.1 drochner } 759 1.1 drochner 760 1.1 drochner if (data->fontwidth != 8 || data->stride != 1) 761 1.1 drochner return (EINVAL); /* XXX 1 byte per line */ 762 1.1 drochner if (data->firstchar != 0 || data->numchars != 256) 763 1.1 drochner return (EINVAL); 764 1.1 drochner #ifndef WSCONS_SUPPORT_PCVTFONTS 765 1.1 drochner if (data->encoding == WSDISPLAY_FONTENC_PCVT) { 766 1.1 drochner printf("vga: pcvt font support not built in, see vga(4)\n"); 767 1.1 drochner return (EINVAL); 768 1.1 drochner } 769 1.1 drochner #endif 770 1.1 drochner 771 1.1 drochner for (slot = 0; slot < 4; slot++) 772 1.1 drochner if (!vc->vc_fonts[slot]) 773 1.1 drochner break; 774 1.1 drochner if (slot == 4) 775 1.1 drochner return (ENOSPC); 776 1.1 drochner 777 1.1 drochner f = malloc(sizeof(struct egafont), M_DEVBUF, M_WAITOK); 778 1.1 drochner strncpy(f->name, data->name, sizeof(f->name)); 779 1.1 drochner f->height = data->fontheight; 780 1.1 drochner f->encoding = data->encoding; 781 1.1 drochner #ifdef notyet 782 1.1 drochner f->firstchar = data->firstchar; 783 1.1 drochner f->numchars = data->numchars; 784 1.1 drochner #endif 785 1.1 drochner #ifdef EGAFONTDEBUG 786 1.1 drochner printf("ega: load %s (8x%d, enc %d) font to slot %d\n", f->name, 787 1.1 drochner f->height, f->encoding, slot); 788 1.1 drochner #endif 789 1.1 drochner vga_loadchars(&vc->hdl, 2 * slot, 0, 256, f->height, data->data); 790 1.1 drochner f->slot = slot; 791 1.1 drochner vc->vc_fonts[slot] = f; 792 1.1 drochner 793 1.1 drochner return (0); 794 1.1 drochner } 795 1.1 drochner 796 1.1 drochner static int 797 1.26 dsl ega_allocattr(void *id, int fg, int bg, int flags, long *attrp) 798 1.1 drochner { 799 1.1 drochner struct egascreen *scr = id; 800 1.1 drochner struct ega_config *vc = scr->cfg; 801 1.1 drochner 802 1.23 mjf if (__predict_false((unsigned int)fg >= sizeof(fgansitopc) || 803 1.23 mjf (unsigned int)bg >= sizeof(bgansitopc))) 804 1.23 mjf return (EINVAL); 805 1.23 mjf 806 1.1 drochner if (vc->hdl.vh_mono) { 807 1.1 drochner if (flags & WSATTR_WSCOLORS) 808 1.1 drochner return (EINVAL); 809 1.1 drochner if (flags & WSATTR_REVERSE) 810 1.1 drochner *attrp = 0x70; 811 1.1 drochner else 812 1.1 drochner *attrp = 0x07; 813 1.1 drochner if (flags & WSATTR_UNDERLINE) 814 1.1 drochner *attrp |= FG_UNDERLINE; 815 1.1 drochner if (flags & WSATTR_HILIT) 816 1.1 drochner *attrp |= FG_INTENSE; 817 1.1 drochner } else { 818 1.1 drochner if (flags & (WSATTR_UNDERLINE | WSATTR_REVERSE)) 819 1.1 drochner return (EINVAL); 820 1.1 drochner if (flags & WSATTR_WSCOLORS) 821 1.1 drochner *attrp = fgansitopc[fg] | bgansitopc[bg]; 822 1.1 drochner else 823 1.1 drochner *attrp = 7; 824 1.1 drochner if (flags & WSATTR_HILIT) 825 1.1 drochner *attrp += 8; 826 1.1 drochner } 827 1.1 drochner if (flags & WSATTR_BLINK) 828 1.1 drochner *attrp |= FG_BLINK; 829 1.1 drochner return (0); 830 1.1 drochner } 831 1.1 drochner 832 1.1 drochner void 833 1.26 dsl ega_copyrows(void *id, int srcrow, int dstrow, int nrows) 834 1.1 drochner { 835 1.1 drochner struct egascreen *scr = id; 836 1.1 drochner bus_space_tag_t memt = scr->pcs.hdl->ph_memt; 837 1.1 drochner bus_space_handle_t memh = scr->pcs.hdl->ph_memh; 838 1.1 drochner int ncols = scr->pcs.type->ncols; 839 1.1 drochner bus_size_t srcoff, dstoff; 840 1.1 drochner 841 1.1 drochner srcoff = srcrow * ncols + 0; 842 1.1 drochner dstoff = dstrow * ncols + 0; 843 1.1 drochner 844 1.1 drochner if (scr->pcs.active) { 845 1.1 drochner if (dstrow == 0 && (srcrow + nrows == scr->pcs.type->nrows)) { 846 1.1 drochner #ifdef PCDISPLAY_SOFTCURSOR 847 1.1 drochner int cursoron = scr->pcs.cursoron; 848 1.1 drochner 849 1.1 drochner if (cursoron) 850 1.1 drochner pcdisplay_cursor(&scr->pcs, 0, 851 1.11 junyoung scr->pcs.cursorrow, scr->pcs.cursorcol); 852 1.1 drochner #endif 853 1.1 drochner /* scroll up whole screen */ 854 1.1 drochner if ((scr->pcs.dispoffset + srcrow * ncols * 2) 855 1.1 drochner <= scr->maxdispoffset) { 856 1.1 drochner scr->pcs.dispoffset += srcrow * ncols * 2; 857 1.1 drochner } else { 858 1.1 drochner bus_space_copy_region_2(memt, memh, 859 1.1 drochner scr->pcs.dispoffset + srcoff * 2, 860 1.1 drochner memh, scr->mindispoffset, 861 1.1 drochner nrows * ncols); 862 1.1 drochner scr->pcs.dispoffset = scr->mindispoffset; 863 1.1 drochner } 864 1.1 drochner vga_6845_write(&scr->cfg->hdl, startadrh, 865 1.1 drochner scr->pcs.dispoffset >> 9); 866 1.1 drochner vga_6845_write(&scr->cfg->hdl, startadrl, 867 1.1 drochner scr->pcs.dispoffset >> 1); 868 1.1 drochner #ifdef PCDISPLAY_SOFTCURSOR 869 1.1 drochner if (cursoron) 870 1.1 drochner pcdisplay_cursor(&scr->pcs, 1, 871 1.11 junyoung scr->pcs.cursorrow, scr->pcs.cursorcol); 872 1.1 drochner #endif 873 1.1 drochner } else { 874 1.1 drochner bus_space_copy_region_2(memt, memh, 875 1.1 drochner scr->pcs.dispoffset + srcoff * 2, 876 1.1 drochner memh, scr->pcs.dispoffset + dstoff * 2, 877 1.1 drochner nrows * ncols); 878 1.1 drochner } 879 1.1 drochner } else 880 1.6 thorpej memcpy(&scr->pcs.mem[dstoff], &scr->pcs.mem[srcoff], 881 1.1 drochner nrows * ncols * 2); 882 1.1 drochner } 883