1 /*- 2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 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 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer as 10 * the first lines of this file unmodified. 11 * 2. 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 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include "opt_syscons.h" 32 #include "opt_vga.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/fbio.h> 38 #include <sys/consio.h> 39 40 #include <machine/bus.h> 41 42 #include <dev/fb/fbreg.h> 43 #include <dev/fb/vgareg.h> 44 #include <dev/syscons/syscons.h> 45 46 #include <isa/isareg.h> 47 48 #ifndef SC_RENDER_DEBUG 49 #define SC_RENDER_DEBUG 0 50 #endif 51 52 static vr_clear_t vga_txtclear; 53 static vr_draw_border_t vga_txtborder; 54 static vr_draw_t vga_txtdraw; 55 static vr_set_cursor_t vga_txtcursor_shape; 56 static vr_draw_cursor_t vga_txtcursor; 57 static vr_blink_cursor_t vga_txtblink; 58 #ifndef SC_NO_CUTPASTE 59 static vr_draw_mouse_t vga_txtmouse; 60 #else 61 #define vga_txtmouse (vr_draw_mouse_t *)vga_nop 62 #endif 63 64 #ifdef SC_PIXEL_MODE 65 static vr_clear_t vga_pxlclear; 66 static vr_draw_border_t vga_pxlborder; 67 static vr_draw_t vga_egadraw; 68 static vr_draw_t vga_vgadraw; 69 static vr_set_cursor_t vga_pxlcursor_shape; 70 static vr_draw_cursor_t vga_pxlcursor; 71 static vr_blink_cursor_t vga_pxlblink; 72 #ifndef SC_NO_CUTPASTE 73 static vr_draw_mouse_t vga_pxlmouse; 74 #else 75 #define vga_pxlmouse (vr_draw_mouse_t *)vga_nop 76 #endif 77 #endif /* SC_PIXEL_MODE */ 78 79 #ifndef SC_NO_MODE_CHANGE 80 static vr_draw_border_t vga_grborder; 81 #endif 82 83 static void vga_nop(scr_stat *scp, ...); 84 85 static sc_rndr_sw_t txtrndrsw = { 86 vga_txtclear, 87 vga_txtborder, 88 vga_txtdraw, 89 vga_txtcursor_shape, 90 vga_txtcursor, 91 vga_txtblink, 92 (vr_set_mouse_t *)vga_nop, 93 vga_txtmouse, 94 }; 95 RENDERER(mda, 0, txtrndrsw, vga_set); 96 RENDERER(cga, 0, txtrndrsw, vga_set); 97 RENDERER(ega, 0, txtrndrsw, vga_set); 98 RENDERER(vga, 0, txtrndrsw, vga_set); 99 100 #ifdef SC_PIXEL_MODE 101 static sc_rndr_sw_t egarndrsw = { 102 vga_pxlclear, 103 vga_pxlborder, 104 vga_egadraw, 105 vga_pxlcursor_shape, 106 vga_pxlcursor, 107 vga_pxlblink, 108 (vr_set_mouse_t *)vga_nop, 109 vga_pxlmouse, 110 }; 111 RENDERER(ega, PIXEL_MODE, egarndrsw, vga_set); 112 113 static sc_rndr_sw_t vgarndrsw = { 114 vga_pxlclear, 115 vga_pxlborder, 116 vga_vgadraw, 117 vga_pxlcursor_shape, 118 vga_pxlcursor, 119 vga_pxlblink, 120 (vr_set_mouse_t *)vga_nop, 121 vga_pxlmouse, 122 }; 123 RENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set); 124 #endif /* SC_PIXEL_MODE */ 125 126 #ifndef SC_NO_MODE_CHANGE 127 static sc_rndr_sw_t grrndrsw = { 128 (vr_clear_t *)vga_nop, 129 vga_grborder, 130 (vr_draw_t *)vga_nop, 131 (vr_set_cursor_t *)vga_nop, 132 (vr_draw_cursor_t *)vga_nop, 133 (vr_blink_cursor_t *)vga_nop, 134 (vr_set_mouse_t *)vga_nop, 135 (vr_draw_mouse_t *)vga_nop, 136 }; 137 RENDERER(cga, GRAPHICS_MODE, grrndrsw, vga_set); 138 RENDERER(ega, GRAPHICS_MODE, grrndrsw, vga_set); 139 RENDERER(vga, GRAPHICS_MODE, grrndrsw, vga_set); 140 #endif /* SC_NO_MODE_CHANGE */ 141 142 RENDERER_MODULE(vga, vga_set); 143 144 #ifndef SC_NO_CUTPASTE 145 #if !defined(SC_ALT_MOUSE_IMAGE) || defined(SC_PIXEL_MODE) 146 static u_short mouse_and_mask[16] = { 147 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 148 0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000 149 }; 150 static u_short mouse_or_mask[16] = { 151 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800, 152 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000 153 }; 154 #endif 155 #endif 156 157 static void 158 vga_nop(scr_stat *scp, ...) 159 { 160 } 161 162 /* text mode renderer */ 163 164 static void 165 vga_txtclear(scr_stat *scp, int c, int attr) 166 { 167 sc_vtb_clear(&scp->scr, c, attr); 168 } 169 170 static void 171 vga_txtborder(scr_stat *scp, int color) 172 { 173 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 174 } 175 176 static void 177 vga_txtdraw(scr_stat *scp, int from, int count, int flip) 178 { 179 vm_offset_t p; 180 int c; 181 int a; 182 183 if (from + count > scp->xsize*scp->ysize) 184 count = scp->xsize*scp->ysize - from; 185 186 if (flip) { 187 for (p = sc_vtb_pointer(&scp->scr, from); count-- > 0; ++from) { 188 c = sc_vtb_getc(&scp->vtb, from); 189 a = sc_vtb_geta(&scp->vtb, from); 190 a = (a & 0x8800) | ((a & 0x7000) >> 4) 191 | ((a & 0x0700) << 4); 192 p = sc_vtb_putchar(&scp->scr, p, c, a); 193 } 194 } else { 195 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count); 196 } 197 } 198 199 static void 200 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink) 201 { 202 if (base < 0 || base >= scp->font_size) 203 return; 204 /* the caller may set height <= 0 in order to disable the cursor */ 205 #if 0 206 scp->curs_attr.base = base; 207 scp->curs_attr.height = height; 208 #endif 209 (*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp, 210 base, height, 211 scp->font_size, blink); 212 } 213 214 static void 215 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip) 216 { 217 sc_softc_t *sc; 218 219 sc = scp->sc; 220 scp->cursor_saveunder_char = c; 221 scp->cursor_saveunder_attr = a; 222 223 #ifndef SC_NO_FONT_LOADING 224 if (scp->curs_attr.flags & CONS_CHAR_CURSOR) { 225 unsigned char *font; 226 int h; 227 int i; 228 229 if (scp->font_size < 14) { 230 font = sc->font_8; 231 h = 8; 232 } else if (scp->font_size >= 16) { 233 font = sc->font_16; 234 h = 16; 235 } else { 236 font = sc->font_14; 237 h = 14; 238 } 239 if (scp->curs_attr.base >= h) 240 return; 241 if (flip) 242 a = (a & 0x8800) 243 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 244 bcopy(font + c*h, font + sc->cursor_char*h, h); 245 font = font + sc->cursor_char*h; 246 for (i = imax(h - scp->curs_attr.base - scp->curs_attr.height, 0); 247 i < h - scp->curs_attr.base; ++i) { 248 font[i] ^= 0xff; 249 } 250 /* XXX */ 251 (*vidsw[sc->adapter]->load_font)(sc->adp, 0, h, font, 252 sc->cursor_char, 1); 253 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a); 254 } else 255 #endif /* SC_NO_FONT_LOADING */ 256 { 257 if ((a & 0x7000) == 0x7000) { 258 a &= 0x8f00; 259 if ((a & 0x0700) == 0) 260 a |= 0x0700; 261 } else { 262 a |= 0x7000; 263 if ((a & 0x0700) == 0x0700) 264 a &= 0xf000; 265 } 266 if (flip) 267 a = (a & 0x8800) 268 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 269 sc_vtb_putc(&scp->scr, at, c, a); 270 } 271 } 272 273 static void 274 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip) 275 { 276 video_adapter_t *adp; 277 int cursor_attr; 278 279 if (scp->curs_attr.height <= 0) /* the text cursor is disabled */ 280 return; 281 282 adp = scp->sc->adp; 283 if (blink) { 284 scp->status |= VR_CURSOR_BLINK; 285 if (on) { 286 scp->status |= VR_CURSOR_ON; 287 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 288 at%scp->xsize, 289 at/scp->xsize); 290 } else { 291 if (scp->status & VR_CURSOR_ON) 292 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 293 -1, -1); 294 scp->status &= ~VR_CURSOR_ON; 295 } 296 } else { 297 scp->status &= ~VR_CURSOR_BLINK; 298 if (on) { 299 scp->status |= VR_CURSOR_ON; 300 draw_txtcharcursor(scp, at, 301 sc_vtb_getc(&scp->scr, at), 302 sc_vtb_geta(&scp->scr, at), 303 flip); 304 } else { 305 cursor_attr = scp->cursor_saveunder_attr; 306 if (flip) 307 cursor_attr = (cursor_attr & 0x8800) 308 | ((cursor_attr & 0x7000) >> 4) 309 | ((cursor_attr & 0x0700) << 4); 310 if (scp->status & VR_CURSOR_ON) 311 sc_vtb_putc(&scp->scr, at, 312 scp->cursor_saveunder_char, 313 cursor_attr); 314 scp->status &= ~VR_CURSOR_ON; 315 } 316 } 317 } 318 319 static void 320 vga_txtblink(scr_stat *scp, int at, int flip) 321 { 322 } 323 324 #ifndef SC_NO_CUTPASTE 325 326 static void 327 draw_txtmouse(scr_stat *scp, int x, int y) 328 { 329 #ifndef SC_ALT_MOUSE_IMAGE 330 if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) { 331 u_char font_buf[128]; 332 u_short cursor[32]; 333 u_char c; 334 int pos; 335 int xoffset, yoffset; 336 int crtc_addr; 337 int i; 338 339 /* prepare mousepointer char's bitmaps */ 340 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 341 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size, 342 &font_buf[0], scp->font_size); 343 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size, 344 &font_buf[32], scp->font_size); 345 bcopy(scp->font 346 + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size, 347 &font_buf[64], scp->font_size); 348 bcopy(scp->font 349 + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size, 350 &font_buf[96], scp->font_size); 351 for (i = 0; i < scp->font_size; ++i) { 352 cursor[i] = font_buf[i]<<8 | font_buf[i+32]; 353 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96]; 354 } 355 356 /* now and-or in the mousepointer image */ 357 xoffset = x%8; 358 yoffset = y%scp->font_size; 359 for (i = 0; i < 16; ++i) { 360 cursor[i + yoffset] = 361 (cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset)) 362 | (mouse_or_mask[i] >> xoffset); 363 } 364 for (i = 0; i < scp->font_size; ++i) { 365 font_buf[i] = (cursor[i] & 0xff00) >> 8; 366 font_buf[i + 32] = cursor[i] & 0xff; 367 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8; 368 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff; 369 } 370 371 #if 1 372 /* wait for vertical retrace to avoid jitter on some videocards */ 373 crtc_addr = scp->sc->adp->va_crtc_addr; 374 while (!(inb(crtc_addr + 6) & 0x08)) /* idle */ ; 375 #endif 376 c = scp->sc->mouse_char; 377 (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf, 378 c, 4); 379 380 sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos)); 381 /* FIXME: may be out of range! */ 382 sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2, 383 sc_vtb_geta(&scp->scr, pos + scp->xsize)); 384 if (x < (scp->xsize - 1)*8) { 385 sc_vtb_putc(&scp->scr, pos + 1, c + 1, 386 sc_vtb_geta(&scp->scr, pos + 1)); 387 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3, 388 sc_vtb_geta(&scp->scr, pos + scp->xsize + 1)); 389 } 390 } else 391 #endif /* SC_ALT_MOUSE_IMAGE */ 392 { 393 /* Red, magenta and brown are mapped to green to to keep it readable */ 394 static const int col_conv[16] = { 395 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14 396 }; 397 int pos; 398 int color; 399 int a; 400 401 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 402 a = sc_vtb_geta(&scp->scr, pos); 403 if (scp->sc->adp->va_flags & V_ADP_COLOR) 404 color = (col_conv[(a & 0xf000) >> 12] << 12) 405 | ((a & 0x0f00) | 0x0800); 406 else 407 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4); 408 sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color); 409 } 410 } 411 412 static void 413 remove_txtmouse(scr_stat *scp, int x, int y) 414 { 415 } 416 417 static void 418 vga_txtmouse(scr_stat *scp, int x, int y, int on) 419 { 420 if (on) 421 draw_txtmouse(scp, x, y); 422 else 423 remove_txtmouse(scp, x, y); 424 } 425 426 #endif /* SC_NO_CUTPASTE */ 427 428 #ifdef SC_PIXEL_MODE 429 430 /* pixel (raster text) mode renderer */ 431 432 static void 433 vga_pxlclear(scr_stat *scp, int c, int attr) 434 { 435 vm_offset_t p; 436 int line_width; 437 int lines; 438 int i; 439 440 /* XXX: we are just filling the screen with the background color... */ 441 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 442 outw(GDCIDX, 0x0003); /* data rotate/function select */ 443 outw(GDCIDX, 0x0f01); /* set/reset enable */ 444 outw(GDCIDX, 0xff08); /* bit mask */ 445 outw(GDCIDX, ((attr & 0xf000) >> 4) | 0x00); /* set/reset */ 446 line_width = scp->sc->adp->va_line_width; 447 lines = scp->ysize*scp->font_size; 448 p = scp->sc->adp->va_window + line_width*scp->yoff*scp->font_size 449 + scp->xoff; 450 for (i = 0; i < lines; ++i) { 451 bzero_io((void *)p, scp->xsize); 452 p += line_width; 453 } 454 outw(GDCIDX, 0x0000); /* set/reset */ 455 outw(GDCIDX, 0x0001); /* set/reset enable */ 456 } 457 458 static void 459 vga_pxlborder(scr_stat *scp, int color) 460 { 461 vm_offset_t p; 462 int line_width; 463 int x; 464 int y; 465 int i; 466 467 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 468 469 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 470 outw(GDCIDX, 0x0003); /* data rotate/function select */ 471 outw(GDCIDX, 0x0f01); /* set/reset enable */ 472 outw(GDCIDX, 0xff08); /* bit mask */ 473 outw(GDCIDX, (color << 8) | 0x00); /* set/reset */ 474 line_width = scp->sc->adp->va_line_width; 475 p = scp->sc->adp->va_window; 476 if (scp->yoff > 0) 477 bzero_io((void *)p, line_width*scp->yoff*scp->font_size); 478 y = (scp->yoff + scp->ysize)*scp->font_size; 479 if (scp->ypixel > y) 480 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y)); 481 y = scp->yoff*scp->font_size; 482 x = scp->xpixel/8 - scp->xoff - scp->xsize; 483 for (i = 0; i < scp->ysize*scp->font_size; ++i) { 484 if (scp->xoff > 0) 485 bzero_io((void *)(p + line_width*(y + i)), scp->xoff); 486 if (x > 0) 487 bzero_io((void *)(p + line_width*(y + i) 488 + scp->xoff + scp->xsize), x); 489 } 490 outw(GDCIDX, 0x0000); /* set/reset */ 491 outw(GDCIDX, 0x0001); /* set/reset enable */ 492 } 493 494 static void 495 vga_egadraw(scr_stat *scp, int from, int count, int flip) 496 { 497 vm_offset_t d; 498 vm_offset_t e; 499 u_char *f; 500 u_short bg; 501 u_short col1, col2; 502 int line_width; 503 int i, j; 504 int a; 505 u_char c; 506 507 line_width = scp->sc->adp->va_line_width; 508 d = scp->sc->adp->va_window 509 + scp->xoff 510 + scp->yoff*scp->font_size*line_width 511 + (from%scp->xsize) 512 + scp->font_size*line_width*(from/scp->xsize); 513 514 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 515 outw(GDCIDX, 0x0003); /* data rotate/function select */ 516 outw(GDCIDX, 0x0f01); /* set/reset enable */ 517 bg = -1; 518 if (from + count > scp->xsize*scp->ysize) 519 count = scp->xsize*scp->ysize - from; 520 for (i = from; count-- > 0; ++i) { 521 a = sc_vtb_geta(&scp->vtb, i); 522 if (flip) { 523 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 524 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 525 } else { 526 col1 = (a & 0x0f00); 527 col2 = (a & 0xf000) >> 4; 528 } 529 /* set background color in EGA/VGA latch */ 530 if (bg != col2) { 531 bg = col2; 532 outw(GDCIDX, bg | 0x00); /* set/reset */ 533 outw(GDCIDX, 0xff08); /* bit mask */ 534 writeb(d, 0); 535 c = readb(d); /* set bg color in the latch */ 536 } 537 /* foreground color */ 538 outw(GDCIDX, col1 | 0x00); /* set/reset */ 539 e = d; 540 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]); 541 for (j = 0; j < scp->font_size; ++j, ++f) { 542 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 543 writeb(e, 0); 544 e += line_width; 545 } 546 ++d; 547 if ((i % scp->xsize) == scp->xsize - 1) 548 d += scp->xoff*2 549 + (scp->font_size - 1)*line_width; 550 } 551 outw(GDCIDX, 0x0000); /* set/reset */ 552 outw(GDCIDX, 0x0001); /* set/reset enable */ 553 outw(GDCIDX, 0xff08); /* bit mask */ 554 } 555 556 static void 557 vga_vgadraw(scr_stat *scp, int from, int count, int flip) 558 { 559 vm_offset_t d; 560 vm_offset_t e; 561 u_char *f; 562 u_short bg; 563 u_short col1, col2; 564 int line_width; 565 int i, j; 566 int a; 567 u_char c; 568 569 line_width = scp->sc->adp->va_line_width; 570 d = scp->sc->adp->va_window 571 + scp->xoff 572 + scp->yoff*scp->font_size*line_width 573 + (from%scp->xsize) 574 + scp->font_size*line_width*(from/scp->xsize); 575 576 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 577 outw(GDCIDX, 0x0003); /* data rotate/function select */ 578 outw(GDCIDX, 0x0f01); /* set/reset enable */ 579 outw(GDCIDX, 0xff08); /* bit mask */ 580 bg = -1; 581 if (from + count > scp->xsize*scp->ysize) 582 count = scp->xsize*scp->ysize - from; 583 for (i = from; count-- > 0; ++i) { 584 a = sc_vtb_geta(&scp->vtb, i); 585 if (flip) { 586 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 587 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 588 } else { 589 col1 = (a & 0x0f00); 590 col2 = (a & 0xf000) >> 4; 591 } 592 /* set background color in EGA/VGA latch */ 593 if (bg != col2) { 594 bg = col2; 595 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 596 outw(GDCIDX, bg | 0x00); /* set/reset */ 597 writeb(d, 0); 598 c = readb(d); /* set bg color in the latch */ 599 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 600 } 601 /* foreground color */ 602 outw(GDCIDX, col1 | 0x00); /* set/reset */ 603 e = d; 604 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]); 605 for (j = 0; j < scp->font_size; ++j, ++f) { 606 writeb(e, *f); 607 e += line_width; 608 } 609 ++d; 610 if ((i % scp->xsize) == scp->xsize - 1) 611 d += scp->xoff*2 612 + (scp->font_size - 1)*line_width; 613 } 614 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 615 outw(GDCIDX, 0x0000); /* set/reset */ 616 outw(GDCIDX, 0x0001); /* set/reset enable */ 617 } 618 619 static void 620 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink) 621 { 622 if (base < 0 || base >= scp->font_size) 623 return; 624 /* the caller may set height <= 0 in order to disable the cursor */ 625 #if 0 626 scp->curs_attr.base = base; 627 scp->curs_attr.height = height; 628 #endif 629 } 630 631 static void 632 draw_pxlcursor(scr_stat *scp, int at, int on, int flip) 633 { 634 vm_offset_t d; 635 u_char *f; 636 int line_width; 637 int height; 638 int col; 639 int a; 640 int i; 641 u_char c; 642 643 line_width = scp->sc->adp->va_line_width; 644 d = scp->sc->adp->va_window 645 + scp->xoff 646 + scp->yoff*scp->font_size*line_width 647 + (at%scp->xsize) 648 + scp->font_size*line_width*(at/scp->xsize) 649 + (scp->font_size - scp->curs_attr.base - 1)*line_width; 650 651 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 652 outw(GDCIDX, 0x0003); /* data rotate/function select */ 653 outw(GDCIDX, 0x0f01); /* set/reset enable */ 654 /* set background color in EGA/VGA latch */ 655 a = sc_vtb_geta(&scp->vtb, at); 656 if (flip) 657 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 658 else 659 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 660 outw(GDCIDX, col | 0x00); /* set/reset */ 661 outw(GDCIDX, 0xff08); /* bit mask */ 662 writeb(d, 0); 663 c = readb(d); /* set bg color in the latch */ 664 /* foreground color */ 665 if (flip) 666 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 667 else 668 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 669 outw(GDCIDX, col | 0x00); /* set/reset */ 670 f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size 671 + scp->font_size - scp->curs_attr.base - 1]); 672 height = imin(scp->curs_attr.height, scp->font_size); 673 for (i = 0; i < height; ++i, --f) { 674 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 675 writeb(d, 0); 676 d -= line_width; 677 } 678 outw(GDCIDX, 0x0000); /* set/reset */ 679 outw(GDCIDX, 0x0001); /* set/reset enable */ 680 outw(GDCIDX, 0xff08); /* bit mask */ 681 } 682 683 static int pxlblinkrate = 0; 684 685 static void 686 vga_pxlcursor(scr_stat *scp, int at, int blink, int on, int flip) 687 { 688 if (scp->curs_attr.height <= 0) /* the text cursor is disabled */ 689 return; 690 691 if (on) { 692 if (!blink) { 693 scp->status |= VR_CURSOR_ON; 694 draw_pxlcursor(scp, at, on, flip); 695 } else if (++pxlblinkrate & 4) { 696 pxlblinkrate = 0; 697 scp->status ^= VR_CURSOR_ON; 698 draw_pxlcursor(scp, at, 699 scp->status & VR_CURSOR_ON, 700 flip); 701 } 702 } else { 703 if (scp->status & VR_CURSOR_ON) 704 draw_pxlcursor(scp, at, on, flip); 705 scp->status &= ~VR_CURSOR_ON; 706 } 707 if (blink) 708 scp->status |= VR_CURSOR_BLINK; 709 else 710 scp->status &= ~VR_CURSOR_BLINK; 711 } 712 713 static void 714 vga_pxlblink(scr_stat *scp, int at, int flip) 715 { 716 if (!(scp->status & VR_CURSOR_BLINK)) 717 return; 718 if (!(++pxlblinkrate & 4)) 719 return; 720 pxlblinkrate = 0; 721 scp->status ^= VR_CURSOR_ON; 722 draw_pxlcursor(scp, at, scp->status & VR_CURSOR_ON, flip); 723 } 724 725 #ifndef SC_NO_CUTPASTE 726 727 static void 728 draw_pxlmouse(scr_stat *scp, int x, int y) 729 { 730 vm_offset_t p; 731 int line_width; 732 int xoff, yoff; 733 int ymax; 734 u_short m; 735 int i, j; 736 737 line_width = scp->sc->adp->va_line_width; 738 xoff = (x - scp->xoff*8)%8; 739 yoff = y - (y/line_width)*line_width; 740 ymax = imin(y + 16, scp->ypixel); 741 742 outw(GDCIDX, 0x0805); /* read mode 1, write mode 0 */ 743 outw(GDCIDX, 0x0001); /* set/reset enable */ 744 outw(GDCIDX, 0x0002); /* color compare */ 745 outw(GDCIDX, 0x0007); /* color don't care */ 746 outw(GDCIDX, 0xff08); /* bit mask */ 747 outw(GDCIDX, 0x0803); /* data rotate/function select (and) */ 748 p = scp->sc->adp->va_window + line_width*y + x/8; 749 if (x < scp->xpixel - 8) { 750 for (i = y, j = 0; i < ymax; ++i, ++j) { 751 m = ~(mouse_and_mask[j] >> xoff); 752 #ifdef __i386__ 753 *(u_char *)p &= m >> 8; 754 *(u_char *)(p + 1) &= m; 755 #elif defined(__alpha__) 756 writeb(p, readb(p) & (m >> 8)); 757 writeb(p + 1, readb(p + 1) & (m >> 8)); 758 #endif 759 p += line_width; 760 } 761 } else { 762 xoff += 8; 763 for (i = y, j = 0; i < ymax; ++i, ++j) { 764 m = ~(mouse_and_mask[j] >> xoff); 765 #ifdef __i386__ 766 *(u_char *)p &= m; 767 #elif defined(__alpha__) 768 writeb(p, readb(p) & (m >> 8)); 769 #endif 770 p += line_width; 771 } 772 } 773 outw(GDCIDX, 0x1003); /* data rotate/function select (or) */ 774 p = scp->sc->adp->va_window + line_width*y + x/8; 775 if (x < scp->xpixel - 8) { 776 for (i = y, j = 0; i < ymax; ++i, ++j) { 777 m = mouse_or_mask[j] >> xoff; 778 #ifdef __i386__ 779 *(u_char *)p &= m >> 8; 780 *(u_char *)(p + 1) &= m; 781 #elif defined(__alpha__) 782 writeb(p, readb(p) & (m >> 8)); 783 writeb(p + 1, readb(p + 1) & (m >> 8)); 784 #endif 785 p += line_width; 786 } 787 } else { 788 for (i = y, j = 0; i < ymax; ++i, ++j) { 789 m = mouse_or_mask[j] >> xoff; 790 #ifdef __i386__ 791 *(u_char *)p &= m; 792 #elif defined(__alpha__) 793 writeb(p, readb(p) & (m >> 8)); 794 #endif 795 p += line_width; 796 } 797 } 798 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 799 outw(GDCIDX, 0x0003); /* data rotate/function select */ 800 } 801 802 static void 803 remove_pxlmouse(scr_stat *scp, int x, int y) 804 { 805 vm_offset_t p; 806 int col, row; 807 int pos; 808 int line_width; 809 int ymax; 810 int i; 811 812 /* erase the mouse cursor image */ 813 col = x/8 - scp->xoff; 814 row = y/scp->font_size - scp->yoff; 815 pos = row*scp->xsize + col; 816 i = (col < scp->xsize - 1) ? 2 : 1; 817 (*scp->rndr->draw)(scp, pos, i, FALSE); 818 if (row < scp->ysize - 1) 819 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 820 821 /* paint border if necessary */ 822 line_width = scp->sc->adp->va_line_width; 823 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 824 outw(GDCIDX, 0x0003); /* data rotate/function select */ 825 outw(GDCIDX, 0x0f01); /* set/reset enable */ 826 outw(GDCIDX, 0xff08); /* bit mask */ 827 outw(GDCIDX, (scp->border << 8) | 0x00); /* set/reset */ 828 if (row == scp->ysize - 1) { 829 i = (scp->ysize + scp->yoff)*scp->font_size; 830 ymax = imin(i + scp->font_size, scp->ypixel); 831 p = scp->sc->adp->va_window + i*line_width + scp->xoff + col; 832 if (col < scp->xsize - 1) { 833 for (; i < ymax; ++i) { 834 writeb(p, 0); 835 writeb(p + 1, 0); 836 p += line_width; 837 } 838 } else { 839 for (; i < ymax; ++i) { 840 writeb(p, 0); 841 p += line_width; 842 } 843 } 844 } 845 if ((col == scp->xsize - 1) && (scp->xoff > 0)) { 846 i = (row + scp->yoff)*scp->font_size; 847 ymax = imin(i + scp->font_size*2, scp->ypixel); 848 p = scp->sc->adp->va_window + i*line_width 849 + scp->xoff + scp->xsize; 850 for (; i < ymax; ++i) { 851 writeb(p, 0); 852 p += line_width; 853 } 854 } 855 outw(GDCIDX, 0x0000); /* set/reset */ 856 outw(GDCIDX, 0x0001); /* set/reset enable */ 857 } 858 859 static void 860 vga_pxlmouse(scr_stat *scp, int x, int y, int on) 861 { 862 if (on) 863 draw_pxlmouse(scp, x, y); 864 else 865 remove_pxlmouse(scp, x, y); 866 } 867 868 #endif /* SC_NO_CUTPASTE */ 869 #endif /* SC_PIXEL_MODE */ 870 871 #ifndef SC_NO_MODE_CHANGE 872 873 /* graphics mode renderer */ 874 875 static void 876 vga_grborder(scr_stat *scp, int color) 877 { 878 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 879 } 880 881 #endif 882