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