1 /*- 2 * (MPSAFE) 3 * 4 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The DragonFly Project 8 * by Sascha Wildner <saw@online.de> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer as 15 * the first lines of this file unmodified. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $FreeBSD: src/sys/dev/syscons/scvgarndr.c,v 1.5.2.3 2001/07/28 12:51:47 yokota Exp $ 32 */ 33 34 #include "opt_syscons.h" 35 #include "opt_vga.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/thread.h> 41 #include <sys/thread2.h> 42 43 #include <machine/console.h> 44 45 #include <dev/video/fb/fbreg.h> 46 #include <dev/video/fb/vgareg.h> 47 #include "syscons.h" 48 49 #include <bus/isa/isareg.h> 50 51 static vr_draw_border_t vga_txtborder; 52 static vr_draw_t vga_txtdraw; 53 static vr_set_cursor_t vga_txtcursor_shape; 54 static vr_draw_cursor_t vga_txtcursor; 55 static vr_blink_cursor_t vga_txtblink; 56 #ifndef SC_NO_CUTPASTE 57 static vr_draw_mouse_t vga_txtmouse; 58 #else 59 #define vga_txtmouse (vr_draw_mouse_t *)vga_nop 60 #endif 61 62 #ifdef SC_PIXEL_MODE 63 static vr_draw_border_t vga_pxlborder_direct; 64 static vr_draw_border_t vga_pxlborder_packed; 65 static vr_draw_border_t vga_pxlborder_planar; 66 static vr_draw_t vga_vgadraw_direct; 67 static vr_draw_t vga_vgadraw_packed; 68 static vr_draw_t vga_vgadraw_planar; 69 static vr_set_cursor_t vga_pxlcursor_shape; 70 static vr_draw_cursor_t vga_pxlcursor_direct; 71 static vr_draw_cursor_t vga_pxlcursor_packed; 72 static vr_draw_cursor_t vga_pxlcursor_planar; 73 static vr_blink_cursor_t vga_pxlblink_direct; 74 static vr_blink_cursor_t vga_pxlblink_packed; 75 static vr_blink_cursor_t vga_pxlblink_planar; 76 #ifndef SC_NO_CUTPASTE 77 static vr_draw_mouse_t vga_pxlmouse_direct; 78 static vr_draw_mouse_t vga_pxlmouse_packed; 79 static vr_draw_mouse_t vga_pxlmouse_planar; 80 #else 81 #define vga_pxlmouse_direct (vr_draw_mouse_t *)vga_nop 82 #define vga_pxlmouse_packed (vr_draw_mouse_t *)vga_nop 83 #define vga_pxlmouse_planar (vr_draw_mouse_t *)vga_nop 84 #endif 85 #endif /* SC_PIXEL_MODE */ 86 87 #ifndef SC_NO_MODE_CHANGE 88 static vr_draw_border_t vga_grborder; 89 #endif 90 91 static void vga_nop(scr_stat *scp, ...); 92 93 static sc_rndr_sw_t txtrndrsw = { 94 vga_txtborder, 95 vga_txtdraw, 96 vga_txtcursor_shape, 97 vga_txtcursor, 98 vga_txtblink, 99 vga_txtmouse, 100 }; 101 RENDERER(vga, V_INFO_MM_TEXT, txtrndrsw, vga_set); 102 103 #ifdef SC_PIXEL_MODE 104 static sc_rndr_sw_t directrndrsw = { 105 vga_pxlborder_direct, 106 vga_vgadraw_direct, 107 vga_pxlcursor_shape, 108 vga_pxlcursor_direct, 109 vga_pxlblink_direct, 110 vga_pxlmouse_direct, 111 }; 112 RENDERER(vga, V_INFO_MM_DIRECT, directrndrsw, vga_set); 113 114 static sc_rndr_sw_t packedrndrsw = { 115 vga_pxlborder_packed, 116 vga_vgadraw_packed, 117 vga_pxlcursor_shape, 118 vga_pxlcursor_packed, 119 vga_pxlblink_packed, 120 vga_pxlmouse_packed, 121 }; 122 RENDERER(vga, V_INFO_MM_PACKED, packedrndrsw, vga_set); 123 124 static sc_rndr_sw_t planarrndrsw = { 125 vga_pxlborder_planar, 126 vga_vgadraw_planar, 127 vga_pxlcursor_shape, 128 vga_pxlcursor_planar, 129 vga_pxlblink_planar, 130 vga_pxlmouse_planar, 131 }; 132 RENDERER(vga, V_INFO_MM_PLANAR, planarrndrsw, vga_set); 133 #endif /* SC_PIXEL_MODE */ 134 135 #ifndef SC_NO_MODE_CHANGE 136 static sc_rndr_sw_t grrndrsw = { 137 vga_grborder, 138 (vr_draw_t *)vga_nop, 139 (vr_set_cursor_t *)vga_nop, 140 (vr_draw_cursor_t *)vga_nop, 141 (vr_blink_cursor_t *)vga_nop, 142 (vr_draw_mouse_t *)vga_nop, 143 }; 144 RENDERER(vga, V_INFO_MM_OTHER, grrndrsw, vga_set); 145 #endif /* SC_NO_MODE_CHANGE */ 146 147 RENDERER_MODULE(vga, vga_set); 148 149 #ifndef SC_NO_CUTPASTE 150 static u_short mouse_and_mask[16] = { 151 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 152 0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000 153 }; 154 static u_short mouse_or_mask[16] = { 155 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800, 156 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000 157 }; 158 #endif 159 160 static void 161 vga_nop(scr_stat *scp, ...) 162 { 163 } 164 165 /* text mode renderer */ 166 167 static void 168 vga_txtborder(scr_stat *scp, int color) 169 { 170 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 171 } 172 173 static void 174 vga_txtdraw(scr_stat *scp, int from, int count, int flip) 175 { 176 uint16_t *p; 177 int c; 178 int a; 179 180 if (from + count > scp->xsize*scp->ysize) 181 count = scp->xsize*scp->ysize - from; 182 183 if (flip) { 184 for (p = scp->scr.vtb_buffer + from; count-- > 0; ++from) { 185 c = sc_vtb_getc(&scp->vtb, from); 186 a = sc_vtb_geta(&scp->vtb, from); 187 a = (a & 0x8800) | ((a & 0x7000) >> 4) 188 | ((a & 0x0700) << 4); 189 p = sc_vtb_putchar(&scp->scr, p, c, a); 190 } 191 } else { 192 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count); 193 } 194 } 195 196 static void 197 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink) 198 { 199 if (base < 0 || base >= scp->font_size) 200 return; 201 202 /* the caller may set height <= 0 in order to disable the cursor */ 203 #if 0 204 scp->cursor_base = base; 205 scp->cursor_height = height; 206 #endif 207 (*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp, 208 base, height, 209 scp->font_size, blink); 210 211 } 212 213 static void 214 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip) 215 { 216 sc_softc_t *sc; 217 218 sc = scp->sc; 219 scp->cursor_saveunder_char = c; 220 scp->cursor_saveunder_attr = a; 221 222 #ifndef SC_NO_FONT_LOADING 223 if (sc->flags & SC_CHAR_CURSOR) { 224 unsigned char *font; 225 int h; 226 int i; 227 228 if (scp->font_size < 14) { 229 font = sc->font_8; 230 h = 8; 231 } else if (scp->font_size >= 16) { 232 font = sc->font_16; 233 h = 16; 234 } else { 235 font = sc->font_14; 236 h = 14; 237 } 238 if (scp->cursor_base >= h) 239 return; 240 if (flip) 241 a = (a & 0x8800) 242 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 243 bcopy(font + c*h, font + sc->cursor_char*h, h); 244 font = font + sc->cursor_char*h; 245 for (i = imax(h - scp->cursor_base - scp->cursor_height, 0); 246 i < h - scp->cursor_base; ++i) { 247 font[i] ^= 0xff; 248 } 249 sc->font_loading_in_progress = TRUE; 250 /* XXX */ 251 (*vidsw[sc->adapter]->load_font)(sc->adp, 0, h, font, 252 sc->cursor_char, 1); 253 sc->font_loading_in_progress = FALSE; 254 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a); 255 } else 256 #endif /* SC_NO_FONT_LOADING */ 257 { 258 if ((a & 0x7000) == 0x7000) { 259 a &= 0x8f00; 260 if ((a & 0x0700) == 0) 261 a |= 0x0700; 262 } else { 263 a |= 0x7000; 264 if ((a & 0x0700) == 0x0700) 265 a &= 0xf000; 266 } 267 if (flip) 268 a = (a & 0x8800) 269 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 270 sc_vtb_putc(&scp->scr, at, c, a); 271 } 272 } 273 274 static void 275 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip) 276 { 277 video_adapter_t *adp; 278 int cursor_attr; 279 280 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 281 return; 282 283 adp = scp->sc->adp; 284 if (blink) { 285 scp->status |= VR_CURSOR_BLINK; 286 if (on) { 287 scp->status |= VR_CURSOR_ON; 288 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 289 at%scp->xsize, 290 at/scp->xsize); 291 } else { 292 if (scp->status & VR_CURSOR_ON) 293 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 294 -1, -1); 295 scp->status &= ~VR_CURSOR_ON; 296 } 297 } else { 298 scp->status &= ~VR_CURSOR_BLINK; 299 if (on) { 300 scp->status |= VR_CURSOR_ON; 301 draw_txtcharcursor(scp, at, 302 sc_vtb_getc(&scp->scr, at), 303 sc_vtb_geta(&scp->scr, at), 304 flip); 305 } else { 306 cursor_attr = scp->cursor_saveunder_attr; 307 if (flip) 308 cursor_attr = (cursor_attr & 0x8800) 309 | ((cursor_attr & 0x7000) >> 4) 310 | ((cursor_attr & 0x0700) << 4); 311 if (scp->status & VR_CURSOR_ON) 312 sc_vtb_putc(&scp->scr, at, 313 scp->cursor_saveunder_char, 314 cursor_attr); 315 scp->status &= ~VR_CURSOR_ON; 316 } 317 } 318 } 319 320 static void 321 vga_txtblink(scr_stat *scp, int at, int flip) 322 { 323 } 324 325 int sc_txtmouse_no_retrace_wait; 326 327 #ifndef SC_NO_CUTPASTE 328 329 static void 330 draw_txtmouse(scr_stat *scp, int x, int y) 331 { 332 #ifndef SC_ALT_MOUSE_IMAGE 333 if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) { 334 u_char font_buf[128]; 335 u_short cursor[32]; 336 u_char c; 337 int pos; 338 int xoffset, yoffset; 339 int i; 340 341 /* prepare mousepointer char's bitmaps */ 342 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 343 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size, 344 &font_buf[0], scp->font_size); 345 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size, 346 &font_buf[32], scp->font_size); 347 bcopy(scp->font 348 + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size, 349 &font_buf[64], scp->font_size); 350 bcopy(scp->font 351 + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size, 352 &font_buf[96], scp->font_size); 353 for (i = 0; i < scp->font_size; ++i) { 354 cursor[i] = font_buf[i]<<8 | font_buf[i+32]; 355 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96]; 356 } 357 358 /* now and-or in the mousepointer image */ 359 xoffset = x%8; 360 yoffset = y%scp->font_size; 361 for (i = 0; i < 16; ++i) { 362 cursor[i + yoffset] = 363 (cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset)) 364 | (mouse_or_mask[i] >> xoffset); 365 } 366 for (i = 0; i < scp->font_size; ++i) { 367 font_buf[i] = (cursor[i] & 0xff00) >> 8; 368 font_buf[i + 32] = cursor[i] & 0xff; 369 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8; 370 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff; 371 } 372 373 #if 1 374 /* wait for vertical retrace to avoid jitter on some videocards */ 375 while (!sc_txtmouse_no_retrace_wait && 376 !(inb(CRTC + 6) & 0x08)) 377 /* idle */ ; 378 #endif 379 c = scp->sc->mouse_char; 380 (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf, 381 c, 4); 382 383 sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos)); 384 /* FIXME: may be out of range! */ 385 sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2, 386 sc_vtb_geta(&scp->scr, pos + scp->xsize)); 387 if (x < (scp->xsize - 1)*8) { 388 sc_vtb_putc(&scp->scr, pos + 1, c + 1, 389 sc_vtb_geta(&scp->scr, pos + 1)); 390 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3, 391 sc_vtb_geta(&scp->scr, pos + scp->xsize + 1)); 392 } 393 } else 394 #endif /* SC_ALT_MOUSE_IMAGE */ 395 { 396 /* Red, magenta and brown are mapped to green to to keep it readable */ 397 static const int col_conv[16] = { 398 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14 399 }; 400 int pos; 401 int color; 402 int a; 403 404 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 405 a = sc_vtb_geta(&scp->scr, pos); 406 if (scp->sc->adp->va_flags & V_ADP_COLOR) 407 color = (col_conv[(a & 0xf000) >> 12] << 12) 408 | ((a & 0x0f00) | 0x0800); 409 else 410 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4); 411 sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color); 412 } 413 414 } 415 416 static void 417 remove_txtmouse(scr_stat *scp, int x, int y) 418 { 419 } 420 421 static void 422 vga_txtmouse(scr_stat *scp, int x, int y, int on) 423 { 424 if (on) 425 draw_txtmouse(scp, x, y); 426 else 427 remove_txtmouse(scp, x, y); 428 } 429 430 #endif /* SC_NO_CUTPASTE */ 431 432 #ifdef SC_PIXEL_MODE 433 434 /* pixel (raster text) mode renderer */ 435 436 static void 437 vga_pxlborder_direct(scr_stat *scp, int color) 438 { 439 int i, x, y; 440 int line_width, pixel_size; 441 uint32_t u32 = 0; 442 vm_offset_t draw_pos, draw_end, p; 443 444 line_width = scp->sc->adp->va_line_width; 445 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 446 447 for (i = 0; i < 4 / pixel_size; ++i) 448 u32 += scp->ega_palette[color] << (i * 8 * pixel_size); 449 450 if (scp->yoff > 0) { 451 draw_pos = scp->sc->adp->va_window; 452 draw_end = draw_pos + line_width * scp->yoff * scp->font_size; 453 454 for (p = draw_pos; p < draw_end; p += 4) 455 writel(p, u32); 456 } 457 458 y = (scp->yoff + scp->ysize) * scp->font_size; 459 460 if (scp->ypixel > y) { 461 draw_pos = scp->sc->adp->va_window + line_width * y; 462 draw_end = draw_pos + line_width * (scp->ypixel - y); 463 464 for (p = draw_pos; p < draw_end; p += 4) 465 writel(p, u32); 466 } 467 468 y = scp->yoff * scp->font_size; 469 x = scp->xpixel / 8 - scp->xoff - scp->xsize; 470 471 for (i = 0; i < scp->ysize * scp->font_size; ++i) { 472 if (scp->xoff > 0) { 473 draw_pos = scp->sc->adp->va_window + 474 line_width * (y + i); 475 draw_end = draw_pos + scp->xoff * 8 * pixel_size; 476 477 for (p = draw_pos; p < draw_end; p += 4) 478 writel(p, u32); 479 } 480 481 if (x > 0) { 482 draw_pos = scp->sc->adp->va_window + 483 line_width * (y + i) + 484 scp->xoff * 8 * pixel_size + 485 scp->xsize * 8 * pixel_size; 486 draw_end = draw_pos + x * 8 * pixel_size; 487 488 for (p = draw_pos; p < draw_end; p += 4) 489 writel(p, u32); 490 } 491 } 492 } 493 494 static void 495 vga_pxlborder_packed(scr_stat *scp, int color) 496 { 497 int i, x, y; 498 int line_width; 499 uint32_t u32; 500 vm_offset_t draw_pos, draw_end, p; 501 502 line_width = scp->sc->adp->va_line_width; 503 u32 = (color << 24) + (color << 16) + (color << 8) + color; 504 505 if (scp->yoff > 0) { 506 draw_pos = scp->sc->adp->va_window; 507 draw_end = draw_pos + line_width * scp->yoff * scp->font_size; 508 509 for (p = draw_pos; p < draw_end; p += 4) 510 writel(p, u32); 511 } 512 513 y = (scp->yoff + scp->ysize) * scp->font_size; 514 515 if (scp->ypixel > y) { 516 draw_pos = scp->sc->adp->va_window + line_width * y; 517 draw_end = draw_pos + line_width * (scp->ypixel - y); 518 519 for (p = draw_pos; p < draw_end; p += 4) 520 writel(p, u32); 521 } 522 523 y = scp->yoff * scp->font_size; 524 x = scp->xpixel / 8 - scp->xoff - scp->xsize; 525 526 for (i = 0; i < scp->ysize * scp->font_size; ++i) { 527 if (scp->xoff > 0) { 528 draw_pos = scp->sc->adp->va_window + 529 line_width * (y + i); 530 draw_end = draw_pos + scp->xoff * 8; 531 532 for (p = draw_pos; p < draw_end; p += 4) 533 writel(p, u32); 534 } 535 536 if (x > 0) { 537 draw_pos = scp->sc->adp->va_window + 538 line_width * (y + i) + scp->xoff * 8 + 539 scp->xsize * 8; 540 draw_end = draw_pos + x * 8; 541 542 for (p = draw_pos; p < draw_end; p += 4) 543 writel(p, u32); 544 } 545 } 546 } 547 548 static void 549 vga_pxlborder_planar(scr_stat *scp, int color) 550 { 551 vm_offset_t p; 552 int line_width; 553 int x; 554 int y; 555 int i; 556 557 lwkt_gettoken(&tty_token); 558 559 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 560 561 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 562 outw(GDCIDX, 0x0003); /* data rotate/function select */ 563 outw(GDCIDX, 0x0f01); /* set/reset enable */ 564 outw(GDCIDX, 0xff08); /* bit mask */ 565 outw(GDCIDX, (color << 8) | 0x00); /* set/reset */ 566 line_width = scp->sc->adp->va_line_width; 567 p = scp->sc->adp->va_window; 568 if (scp->yoff > 0) 569 bzero_io((void *)p, line_width*scp->yoff*scp->font_size); 570 y = (scp->yoff + scp->ysize)*scp->font_size; 571 if (scp->ypixel > y) 572 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y)); 573 y = scp->yoff*scp->font_size; 574 x = scp->xpixel/8 - scp->xoff - scp->xsize; 575 for (i = 0; i < scp->ysize*scp->font_size; ++i) { 576 if (scp->xoff > 0) 577 bzero_io((void *)(p + line_width*(y + i)), scp->xoff); 578 if (x > 0) 579 bzero_io((void *)(p + line_width*(y + i) 580 + scp->xoff + scp->xsize), x); 581 } 582 outw(GDCIDX, 0x0000); /* set/reset */ 583 outw(GDCIDX, 0x0001); /* set/reset enable */ 584 lwkt_reltoken(&tty_token); 585 } 586 587 static void 588 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip) 589 { 590 int line_width, pixel_size; 591 int a, i, j, k, l, pos; 592 uint32_t fg, bg, u32; 593 unsigned char *char_data; 594 vm_offset_t draw_pos, p; 595 596 line_width = scp->sc->adp->va_line_width; 597 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 598 599 draw_pos = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size); 600 601 if (from + count > scp->xsize * scp->ysize) 602 count = scp->xsize * scp->ysize - from; 603 604 for (i = from; count-- > 0; ++i) { 605 a = sc_vtb_geta(&scp->vtb, i); 606 607 if (flip) { 608 fg = scp->ega_palette[(((a & 0x7000) >> 4) | 609 (a & 0x0800)) >> 8]; 610 bg = scp->ega_palette[(((a & 0x8000) >> 4) | 611 (a & 0x0700)) >> 8]; 612 } else { 613 fg = scp->ega_palette[(a & 0x0f00) >> 8]; 614 bg = scp->ega_palette[(a & 0xf000) >> 12]; 615 } 616 617 p = draw_pos; 618 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 619 scp->font_size]); 620 621 for (j = 0; j < scp->font_size; ++j, ++char_data) { 622 pos = 7; 623 624 for (k = 0; k < 2 * pixel_size; ++k) { 625 u32 = 0; 626 627 for (l = 0; l < 4 / pixel_size; ++l) { 628 u32 += (*char_data & (1 << pos--) ? 629 fg : bg) << (l * 8 * pixel_size); 630 } 631 632 writel(p, u32); 633 p += 4; 634 } 635 636 p += line_width - 8 * pixel_size; 637 } 638 639 draw_pos += 8 * pixel_size; 640 641 if ((i % scp->xsize) == scp->xsize - 1) 642 draw_pos += scp->xoff * 16 * pixel_size + 643 (scp->font_size - 1) * line_width; 644 } 645 } 646 647 static void 648 vga_vgadraw_packed(scr_stat *scp, int from, int count, int flip) 649 { 650 int line_width; 651 int a, i, j; 652 uint32_t fg, bg, u32; 653 unsigned char *char_data; 654 vm_offset_t draw_pos, p; 655 656 line_width = scp->sc->adp->va_line_width; 657 658 draw_pos = VIDEO_MEMORY_POS(scp, from, 8); 659 660 if (from + count > scp->xsize * scp->ysize) 661 count = scp->xsize * scp->ysize - from; 662 663 for (i = from; count-- > 0; ++i) { 664 a = sc_vtb_geta(&scp->vtb, i); 665 666 if (flip) { 667 fg = ((a & 0xf000) >> 4) >> 8; 668 bg = (a & 0x0f00) >> 8; 669 } else { 670 fg = (a & 0x0f00) >> 8; 671 bg = ((a & 0xf000) >> 4) >> 8; 672 } 673 674 p = draw_pos; 675 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 676 scp->font_size]); 677 678 for (j = 0; j < scp->font_size; ++j, ++char_data) { 679 u32 = ((*char_data & 1 ? fg : bg) << 24) + 680 ((*char_data & 2 ? fg : bg) << 16) + 681 ((*char_data & 4 ? fg : bg) << 8) + 682 (*char_data & 8 ? fg : bg); 683 writel(p + 4, u32); 684 685 u32 = ((*char_data & 16 ? fg : bg) << 24) + 686 ((*char_data & 32 ? fg : bg) << 16) + 687 ((*char_data & 64 ? fg : bg) << 8) + 688 (*char_data & 128 ? fg : bg); 689 writel(p, u32); 690 691 p += line_width; 692 } 693 694 draw_pos += 8; 695 696 if ((i % scp->xsize) == scp->xsize - 1) 697 draw_pos += scp->xoff * 16 + 698 (scp->font_size - 1) * line_width; 699 } 700 } 701 702 static void 703 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip) 704 { 705 vm_offset_t d; 706 vm_offset_t e; 707 u_char *f; 708 u_short bg; 709 u_short col1, col2; 710 int line_width; 711 int i, j; 712 int a; 713 u_char c; 714 715 d = VIDEO_MEMORY_POS(scp, from, 1); 716 717 line_width = scp->sc->adp->va_line_width; 718 719 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 720 outw(GDCIDX, 0x0003); /* data rotate/function select */ 721 outw(GDCIDX, 0x0f01); /* set/reset enable */ 722 outw(GDCIDX, 0xff08); /* bit mask */ 723 bg = -1; 724 if (from + count > scp->xsize*scp->ysize) 725 count = scp->xsize*scp->ysize - from; 726 for (i = from; count-- > 0; ++i) { 727 a = sc_vtb_geta(&scp->vtb, i); 728 if (flip) { 729 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 730 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 731 } else { 732 col1 = (a & 0x0f00); 733 col2 = (a & 0xf000) >> 4; 734 } 735 /* set background color in EGA/VGA latch */ 736 if (bg != col2) { 737 bg = col2; 738 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 739 outw(GDCIDX, bg | 0x00); /* set/reset */ 740 writeb(d, 0); 741 c = readb(d); /* set bg color in the latch */ 742 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 743 } 744 /* foreground color */ 745 outw(GDCIDX, col1 | 0x00); /* set/reset */ 746 e = d; 747 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]); 748 for (j = 0; j < scp->font_size; ++j, ++f) { 749 writeb(e, *f); 750 e += line_width; 751 } 752 ++d; 753 if ((i % scp->xsize) == scp->xsize - 1) 754 d += scp->xoff*2 755 + (scp->font_size - 1)*line_width; 756 } 757 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 758 outw(GDCIDX, 0x0000); /* set/reset */ 759 outw(GDCIDX, 0x0001); /* set/reset enable */ 760 } 761 762 static void 763 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink) 764 { 765 if (base < 0 || base >= scp->font_size) 766 return; 767 /* the caller may set height <= 0 in order to disable the cursor */ 768 #if 0 769 scp->cursor_base = base; 770 scp->cursor_height = height; 771 #endif 772 } 773 774 static void 775 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip) 776 { 777 int line_width, pixel_size, height; 778 int a, i, j, k, pos; 779 uint32_t fg, bg, u32; 780 unsigned char *char_data; 781 vm_offset_t draw_pos; 782 783 line_width = scp->sc->adp->va_line_width; 784 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 785 786 draw_pos = VIDEO_MEMORY_POS(scp, at, 8 * pixel_size) + 787 (scp->font_size - scp->cursor_base - 1) * line_width; 788 789 a = sc_vtb_geta(&scp->vtb, at); 790 791 if (flip) { 792 fg = scp->ega_palette[((on) ? (a & 0x0f00) : 793 ((a & 0xf000) >> 4)) >> 8]; 794 bg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 795 (a & 0x0f00)) >> 8]; 796 } else { 797 fg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 798 (a & 0x0f00)) >> 8]; 799 bg = scp->ega_palette[((on) ? (a & 0x0f00) : 800 ((a & 0xf000) >> 4)) >> 8]; 801 } 802 803 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size + 804 scp->font_size - scp->cursor_base - 1]); 805 806 height = imin(scp->cursor_height, scp->font_size); 807 808 for (i = 0; i < height; ++i, --char_data) { 809 pos = 7; 810 811 for (j = 0; j < 2 * pixel_size; ++j) { 812 u32 = 0; 813 814 for (k = 0; k < 4 / pixel_size; ++k) { 815 u32 += (*char_data & (1 << pos--) ? 816 fg : bg) << (k * 8 * pixel_size); 817 } 818 819 writel(draw_pos, u32); 820 draw_pos += 4; 821 } 822 823 draw_pos -= line_width + 8 * pixel_size; 824 } 825 } 826 827 static void 828 draw_pxlcursor_packed(scr_stat *scp, int at, int on, int flip) 829 { 830 int line_width, height; 831 int a, i; 832 uint32_t fg, bg, u32; 833 unsigned char *char_data; 834 vm_offset_t draw_pos; 835 836 line_width = scp->sc->adp->va_line_width; 837 838 draw_pos = VIDEO_MEMORY_POS(scp, at, 8) + 839 (scp->font_size - scp->cursor_base - 1) * line_width; 840 841 a = sc_vtb_geta(&scp->vtb, at); 842 843 if (flip) { 844 fg = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8; 845 bg = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8; 846 } else { 847 fg = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8; 848 bg = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8; 849 } 850 851 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size + 852 scp->font_size - scp->cursor_base - 1]); 853 854 height = imin(scp->cursor_height, scp->font_size); 855 856 for (i = 0; i < height; ++i, --char_data) { 857 u32 = ((*char_data & 1 ? fg : bg) << 24) + 858 ((*char_data & 2 ? fg : bg) << 16) + 859 ((*char_data & 4 ? fg : bg) << 8) + 860 (*char_data & 8 ? fg : bg); 861 writel(draw_pos + 4, u32); 862 863 u32 = ((*char_data & 16 ? fg : bg) << 24) + 864 ((*char_data & 32 ? fg : bg) << 16) + 865 ((*char_data & 64 ? fg : bg) << 8) + 866 (*char_data & 128 ? fg : bg); 867 writel(draw_pos, u32); 868 869 draw_pos -= line_width; 870 } 871 } 872 873 static void 874 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip) 875 { 876 vm_offset_t d; 877 u_char *f; 878 int line_width; 879 int height; 880 int col; 881 int a; 882 int i; 883 u_char c; 884 885 line_width = scp->sc->adp->va_line_width; 886 887 d = VIDEO_MEMORY_POS(scp, at, 1) + 888 (scp->font_size - scp->cursor_base - 1) * line_width; 889 890 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 891 outw(GDCIDX, 0x0003); /* data rotate/function select */ 892 outw(GDCIDX, 0x0f01); /* set/reset enable */ 893 /* set background color in EGA/VGA latch */ 894 a = sc_vtb_geta(&scp->vtb, at); 895 if (flip) 896 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 897 else 898 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 899 outw(GDCIDX, col | 0x00); /* set/reset */ 900 outw(GDCIDX, 0xff08); /* bit mask */ 901 writeb(d, 0); 902 c = readb(d); /* set bg color in the latch */ 903 /* foreground color */ 904 if (flip) 905 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 906 else 907 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 908 outw(GDCIDX, col | 0x00); /* set/reset */ 909 f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size 910 + scp->font_size - scp->cursor_base - 1]); 911 height = imin(scp->cursor_height, scp->font_size); 912 for (i = 0; i < height; ++i, --f) { 913 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 914 writeb(d, 0); 915 d -= line_width; 916 } 917 outw(GDCIDX, 0x0000); /* set/reset */ 918 outw(GDCIDX, 0x0001); /* set/reset enable */ 919 outw(GDCIDX, 0xff08); /* bit mask */ 920 } 921 922 static int pxlblinkrate = 0; 923 924 static void 925 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip) 926 { 927 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 928 return; 929 930 if (on) { 931 if (!blink) { 932 scp->status |= VR_CURSOR_ON; 933 draw_pxlcursor_direct(scp, at, on, flip); 934 } else if (++pxlblinkrate & 4) { 935 pxlblinkrate = 0; 936 scp->status ^= VR_CURSOR_ON; 937 draw_pxlcursor_direct(scp, at, 938 scp->status & VR_CURSOR_ON, 939 flip); 940 } 941 } else { 942 if (scp->status & VR_CURSOR_ON) 943 draw_pxlcursor_direct(scp, at, on, flip); 944 scp->status &= ~VR_CURSOR_ON; 945 } 946 if (blink) 947 scp->status |= VR_CURSOR_BLINK; 948 else 949 scp->status &= ~VR_CURSOR_BLINK; 950 } 951 952 static void 953 vga_pxlcursor_packed(scr_stat *scp, int at, int blink, int on, int flip) 954 { 955 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 956 return; 957 958 if (on) { 959 if (!blink) { 960 scp->status |= VR_CURSOR_ON; 961 draw_pxlcursor_packed(scp, at, on, flip); 962 } else if (++pxlblinkrate & 4) { 963 pxlblinkrate = 0; 964 scp->status ^= VR_CURSOR_ON; 965 draw_pxlcursor_packed(scp, at, 966 scp->status & VR_CURSOR_ON, 967 flip); 968 } 969 } else { 970 if (scp->status & VR_CURSOR_ON) 971 draw_pxlcursor_packed(scp, at, on, flip); 972 scp->status &= ~VR_CURSOR_ON; 973 } 974 if (blink) 975 scp->status |= VR_CURSOR_BLINK; 976 else 977 scp->status &= ~VR_CURSOR_BLINK; 978 } 979 980 static void 981 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip) 982 { 983 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 984 return; 985 986 if (on) { 987 if (!blink) { 988 scp->status |= VR_CURSOR_ON; 989 draw_pxlcursor_planar(scp, at, on, flip); 990 } else if (++pxlblinkrate & 4) { 991 pxlblinkrate = 0; 992 scp->status ^= VR_CURSOR_ON; 993 draw_pxlcursor_planar(scp, at, 994 scp->status & VR_CURSOR_ON, 995 flip); 996 } 997 } else { 998 if (scp->status & VR_CURSOR_ON) 999 draw_pxlcursor_planar(scp, at, on, flip); 1000 scp->status &= ~VR_CURSOR_ON; 1001 } 1002 if (blink) 1003 scp->status |= VR_CURSOR_BLINK; 1004 else 1005 scp->status &= ~VR_CURSOR_BLINK; 1006 } 1007 1008 static void 1009 vga_pxlblink_direct(scr_stat *scp, int at, int flip) 1010 { 1011 if (!(scp->status & VR_CURSOR_BLINK)) 1012 return; 1013 if (!(++pxlblinkrate & 4)) 1014 return; 1015 pxlblinkrate = 0; 1016 scp->status ^= VR_CURSOR_ON; 1017 draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip); 1018 } 1019 1020 static void 1021 vga_pxlblink_packed(scr_stat *scp, int at, int flip) 1022 { 1023 if (!(scp->status & VR_CURSOR_BLINK)) 1024 return; 1025 if (!(++pxlblinkrate & 4)) 1026 return; 1027 pxlblinkrate = 0; 1028 scp->status ^= VR_CURSOR_ON; 1029 draw_pxlcursor_packed(scp, at, scp->status & VR_CURSOR_ON, flip); 1030 } 1031 1032 static void 1033 vga_pxlblink_planar(scr_stat *scp, int at, int flip) 1034 { 1035 if (!(scp->status & VR_CURSOR_BLINK)) 1036 return; 1037 if (!(++pxlblinkrate & 4)) 1038 return; 1039 pxlblinkrate = 0; 1040 scp->status ^= VR_CURSOR_ON; 1041 draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip); 1042 } 1043 1044 #ifndef SC_NO_CUTPASTE 1045 1046 static void 1047 draw_pxlmouse_direct(scr_stat *scp, int x, int y) 1048 { 1049 int line_width, pixel_size; 1050 int xend, yend; 1051 int i, j; 1052 vm_offset_t draw_pos; 1053 1054 line_width = scp->sc->adp->va_line_width; 1055 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 1056 1057 xend = imin(x + 8, 8 * (scp->xoff + scp->xsize)); 1058 yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 1059 1060 draw_pos = scp->sc->adp->va_window + y * line_width + x * pixel_size; 1061 1062 for (i = 0; i < (yend - y); i++) { 1063 for (j = (xend - x - 1); j >= 0; j--) { 1064 switch (scp->sc->adp->va_info.vi_depth) { 1065 case 32: 1066 if (mouse_or_mask[i] & 1 << (15 - j)) 1067 writel(draw_pos + 4 * j, 1068 scp->ega_palette[15]); 1069 else if (mouse_and_mask[i] & 1 << (15 - j)) 1070 writel(draw_pos + 4 * j, 1071 scp->ega_palette[0]); 1072 break; 1073 case 16: 1074 /* FALLTHROUGH */ 1075 case 15: 1076 if (mouse_or_mask[i] & 1 << (15 - j)) 1077 writew(draw_pos + 2 * j, 1078 scp->ega_palette[15]); 1079 else if (mouse_and_mask[i] & 1 << (15 - j)) 1080 writew(draw_pos + 2 * j, 1081 scp->ega_palette[0]); 1082 break; 1083 } 1084 } 1085 1086 draw_pos += line_width; 1087 } 1088 } 1089 1090 static void 1091 draw_pxlmouse_packed(scr_stat *scp, int x, int y) 1092 { 1093 int line_width; 1094 int xend, yend; 1095 int i, j; 1096 vm_offset_t draw_pos; 1097 1098 line_width = scp->sc->adp->va_line_width; 1099 1100 xend = imin(8 * (scp->xoff + scp->xsize), imin(x + 16, scp->xpixel)); 1101 yend = imin(scp->font_size * (scp->yoff + scp->ysize), 1102 imin(y + 16, scp->ypixel)); 1103 1104 draw_pos = scp->sc->adp->va_window + y * line_width + x; 1105 1106 for (i = 0; i < (yend - y); i++) { 1107 for (j = (xend - x - 1); j >= 0; j--) { 1108 if (mouse_or_mask[i] & 1 << (15 - j)) 1109 writeb(draw_pos + j, 15); 1110 else if (mouse_and_mask[i] & 1 << (15 - j)) 1111 writeb(draw_pos + j, 0); 1112 } 1113 1114 draw_pos += line_width; 1115 } 1116 } 1117 1118 static void 1119 draw_pxlmouse_planar(scr_stat *scp, int x, int y) 1120 { 1121 vm_offset_t p; 1122 int line_width; 1123 int xoff; 1124 int ymax; 1125 u_short m; 1126 int i, j; 1127 1128 line_width = scp->sc->adp->va_line_width; 1129 xoff = (x - scp->xoff*8)%8; 1130 ymax = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 1131 1132 outw(GDCIDX, 0x0805); /* read mode 1, write mode 0 */ 1133 outw(GDCIDX, 0x0001); /* set/reset enable */ 1134 outw(GDCIDX, 0x0002); /* color compare */ 1135 outw(GDCIDX, 0x0007); /* color don't care */ 1136 outw(GDCIDX, 0xff08); /* bit mask */ 1137 outw(GDCIDX, 0x0803); /* data rotate/function select (and) */ 1138 p = scp->sc->adp->va_window + line_width*y + x/8; 1139 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1140 for (i = y, j = 0; i < ymax; ++i, ++j) { 1141 m = ~(mouse_and_mask[j] >> xoff); 1142 *(u_char *)p &= m >> 8; 1143 *(u_char *)(p + 1) &= m; 1144 p += line_width; 1145 } 1146 } else { 1147 xoff += 8; 1148 for (i = y, j = 0; i < ymax; ++i, ++j) { 1149 m = ~(mouse_and_mask[j] >> xoff); 1150 *(u_char *)p &= m; 1151 p += line_width; 1152 } 1153 } 1154 outw(GDCIDX, 0x1003); /* data rotate/function select (or) */ 1155 p = scp->sc->adp->va_window + line_width*y + x/8; 1156 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1157 for (i = y, j = 0; i < ymax; ++i, ++j) { 1158 m = mouse_or_mask[j] >> xoff; 1159 *(u_char *)p &= m >> 8; 1160 *(u_char *)(p + 1) &= m; 1161 p += line_width; 1162 } 1163 } else { 1164 for (i = y, j = 0; i < ymax; ++i, ++j) { 1165 m = mouse_or_mask[j] >> xoff; 1166 *(u_char *)p &= m; 1167 p += line_width; 1168 } 1169 } 1170 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 1171 outw(GDCIDX, 0x0003); /* data rotate/function select */ 1172 } 1173 1174 static void 1175 remove_pxlmouse(scr_stat *scp, int x, int y) 1176 { 1177 int col, row; 1178 int pos; 1179 int i; 1180 1181 /* erase the mouse cursor image */ 1182 col = x/8 - scp->xoff; 1183 row = y/scp->font_size - scp->yoff; 1184 pos = row*scp->xsize + col; 1185 i = (col < scp->xsize - 1) ? 2 : 1; 1186 (*scp->rndr->draw)(scp, pos, i, FALSE); 1187 if (row < scp->ysize - 1) 1188 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 1189 } 1190 1191 static void 1192 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on) 1193 { 1194 if (on) 1195 draw_pxlmouse_direct(scp, x, y); 1196 else 1197 remove_pxlmouse(scp, x, y); 1198 } 1199 1200 static void 1201 vga_pxlmouse_packed(scr_stat *scp, int x, int y, int on) 1202 { 1203 if (on) 1204 draw_pxlmouse_packed(scp, x, y); 1205 else 1206 remove_pxlmouse(scp, x, y); 1207 } 1208 1209 static void 1210 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on) 1211 { 1212 if (on) 1213 draw_pxlmouse_planar(scp, x, y); 1214 else 1215 remove_pxlmouse(scp, x, y); 1216 } 1217 1218 #endif /* SC_NO_CUTPASTE */ 1219 #endif /* SC_PIXEL_MODE */ 1220 1221 #ifndef SC_NO_MODE_CHANGE 1222 1223 /* graphics mode renderer */ 1224 1225 static void 1226 vga_grborder(scr_stat *scp, int color) 1227 { 1228 lwkt_gettoken(&tty_token); 1229 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 1230 lwkt_reltoken(&tty_token); 1231 } 1232 1233 #endif 1234