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_height) 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_height, 210 blink); 211 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 (sc->flags & SC_CHAR_CURSOR) { 225 unsigned char *font; 226 int h; 227 int i; 228 229 if (scp->font_height < 14) { 230 font = sc->font_8; 231 h = 8; 232 } else if (scp->font_height >= 16) { 233 font = sc->font_16; 234 h = 16; 235 } else { 236 font = sc->font_14; 237 h = 14; 238 } 239 if (scp->cursor_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->cursor_base - scp->cursor_height, 0); 247 i < h - scp->cursor_base; ++i) { 248 font[i] ^= 0xff; 249 } 250 sc->font_loading_in_progress = TRUE; 251 /* XXX */ 252 (*vidsw[sc->adapter]->load_font)(sc->adp, 0, h, font, 253 sc->cursor_char, 1); 254 sc->font_loading_in_progress = FALSE; 255 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a); 256 } else 257 #endif /* SC_NO_FONT_LOADING */ 258 { 259 if ((a & 0x7000) == 0x7000) { 260 a &= 0x8f00; 261 if ((a & 0x0700) == 0) 262 a |= 0x0700; 263 } else { 264 a |= 0x7000; 265 if ((a & 0x0700) == 0x0700) 266 a &= 0xf000; 267 } 268 if (flip) 269 a = (a & 0x8800) 270 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 271 sc_vtb_putc(&scp->scr, at, c, a); 272 } 273 } 274 275 static void 276 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip) 277 { 278 video_adapter_t *adp; 279 int cursor_attr; 280 281 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 282 return; 283 284 adp = scp->sc->adp; 285 if (blink) { 286 scp->status |= VR_CURSOR_BLINK; 287 if (on) { 288 scp->status |= VR_CURSOR_ON; 289 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 290 at%scp->xsize, 291 at/scp->xsize); 292 } else { 293 if (scp->status & VR_CURSOR_ON) 294 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 295 -1, -1); 296 scp->status &= ~VR_CURSOR_ON; 297 } 298 } else { 299 scp->status &= ~VR_CURSOR_BLINK; 300 if (on) { 301 scp->status |= VR_CURSOR_ON; 302 draw_txtcharcursor(scp, at, 303 sc_vtb_getc(&scp->scr, at), 304 sc_vtb_geta(&scp->scr, at), 305 flip); 306 } else { 307 cursor_attr = scp->cursor_saveunder_attr; 308 if (flip) 309 cursor_attr = (cursor_attr & 0x8800) 310 | ((cursor_attr & 0x7000) >> 4) 311 | ((cursor_attr & 0x0700) << 4); 312 if (scp->status & VR_CURSOR_ON) 313 sc_vtb_putc(&scp->scr, at, 314 scp->cursor_saveunder_char, 315 cursor_attr); 316 scp->status &= ~VR_CURSOR_ON; 317 } 318 } 319 } 320 321 static void 322 vga_txtblink(scr_stat *scp, int at, int flip) 323 { 324 } 325 326 int sc_txtmouse_no_retrace_wait; 327 328 #ifndef SC_NO_CUTPASTE 329 330 static void 331 draw_txtmouse(scr_stat *scp, int x, int y) 332 { 333 #ifndef SC_ALT_MOUSE_IMAGE 334 if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) { 335 u_char font_buf[128]; 336 u_short cursor[32]; 337 u_char c; 338 int pos; 339 int xoffset, yoffset; 340 int i; 341 342 /* prepare mousepointer char's bitmaps */ 343 pos = (y / scp->font_height - scp->yoff) * scp->xsize + 344 x / scp->font_width - scp->xoff; 345 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos) * scp->font_height, 346 &font_buf[0], scp->font_height); 347 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1) * scp->font_height, 348 &font_buf[32], scp->font_height); 349 bcopy(scp->font 350 + sc_vtb_getc(&scp->scr, pos + scp->xsize) * scp->font_height, 351 &font_buf[64], scp->font_height); 352 bcopy(scp->font + 353 sc_vtb_getc(&scp->scr, pos + scp->xsize + 1) * scp->font_height, 354 &font_buf[96], scp->font_height); 355 for (i = 0; i < scp->font_height; ++i) { 356 cursor[i] = (font_buf[i]<<8) | font_buf[i+32]; 357 cursor[i + scp->font_height] = (font_buf[i+64]<<8) | 358 font_buf[i+96]; 359 } 360 361 /* now and-or in the mousepointer image */ 362 xoffset = x % scp->font_width; 363 yoffset = y % scp->font_height; 364 for (i = 0; i < 16; ++i) { 365 cursor[i + yoffset] = 366 (cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset)) 367 | (mouse_or_mask[i] >> xoffset); 368 } 369 for (i = 0; i < scp->font_height; ++i) { 370 font_buf[i] = (cursor[i] & 0xff00) >> 8; 371 font_buf[i + 32] = cursor[i] & 0xff; 372 font_buf[i + 64] = (cursor[i + scp->font_height] & 0xff00) >> 8; 373 font_buf[i + 96] = cursor[i + scp->font_height] & 0xff; 374 } 375 376 #if 1 377 /* wait for vertical retrace to avoid jitter on some videocards */ 378 while (!sc_txtmouse_no_retrace_wait && 379 !(inb(CRTC + 6) & 0x08)) 380 /* idle */ ; 381 #endif 382 c = scp->sc->mouse_char; 383 (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf, 384 c, 4); 385 386 sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos)); 387 /* FIXME: may be out of range! */ 388 sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2, 389 sc_vtb_geta(&scp->scr, pos + scp->xsize)); 390 if (x < (scp->xsize - 1)*8) { 391 sc_vtb_putc(&scp->scr, pos + 1, c + 1, 392 sc_vtb_geta(&scp->scr, pos + 1)); 393 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3, 394 sc_vtb_geta(&scp->scr, pos + scp->xsize + 1)); 395 } 396 } else 397 #endif /* SC_ALT_MOUSE_IMAGE */ 398 { 399 /* Red, magenta and brown are mapped to green to to keep it readable */ 400 static const int col_conv[16] = { 401 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14 402 }; 403 int pos; 404 int color; 405 int a; 406 407 pos = (y / scp->font_height - scp->yoff)* 408 scp->xsize + x / scp->font_width - scp->xoff; 409 a = sc_vtb_geta(&scp->scr, pos); 410 if (scp->sc->adp->va_flags & V_ADP_COLOR) 411 color = (col_conv[(a & 0xf000) >> 12] << 12) 412 | ((a & 0x0f00) | 0x0800); 413 else 414 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4); 415 sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color); 416 } 417 418 } 419 420 static void 421 remove_txtmouse(scr_stat *scp, int x, int y) 422 { 423 } 424 425 static void 426 vga_txtmouse(scr_stat *scp, int x, int y, int on) 427 { 428 if (on) 429 draw_txtmouse(scp, x, y); 430 else 431 remove_txtmouse(scp, x, y); 432 } 433 434 #endif /* SC_NO_CUTPASTE */ 435 436 #ifdef SC_PIXEL_MODE 437 438 /* pixel (raster text) mode renderer */ 439 440 static void 441 vga_pxlborder_direct(scr_stat *scp, int color) 442 { 443 int i, x, y; 444 int line_width, pixel_size; 445 uint32_t u32 = 0; 446 vm_offset_t draw_pos, draw_end, p; 447 448 line_width = scp->sc->adp->va_line_width; 449 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 450 451 for (i = 0; i < 4 / pixel_size; ++i) 452 u32 += scp->ega_palette[color] << (i * 8 * pixel_size); 453 454 if (scp->yoff > 0) { 455 draw_pos = scp->sc->adp->va_window; 456 draw_end = draw_pos + line_width * scp->yoff * scp->font_height; 457 458 for (p = draw_pos; p < draw_end; p += 4) 459 writel(p, u32); 460 } 461 462 y = (scp->yoff + scp->ysize) * scp->font_height; 463 464 if (scp->ypixel > y) { 465 draw_pos = scp->sc->adp->va_window + line_width * y; 466 draw_end = draw_pos + line_width * (scp->ypixel - y); 467 468 for (p = draw_pos; p < draw_end; p += 4) 469 writel(p, u32); 470 } 471 472 y = scp->yoff * scp->font_height; 473 x = scp->xpixel / scp->font_width - scp->xoff - scp->xsize; 474 475 for (i = 0; i < scp->ysize * scp->font_height; ++i) { 476 if (scp->xoff > 0) { 477 draw_pos = scp->sc->adp->va_window + 478 line_width * (y + i); 479 draw_end = draw_pos + 480 scp->xoff * scp->font_width * pixel_size; 481 482 for (p = draw_pos; p < draw_end; p += 4) 483 writel(p, u32); 484 } 485 486 if (x > 0) { 487 draw_pos = scp->sc->adp->va_window + 488 line_width * (y + i) + 489 scp->xoff * 8 * pixel_size + 490 scp->xsize * 8 * pixel_size; 491 draw_end = draw_pos + x * 8 * pixel_size; 492 493 for (p = draw_pos; p < draw_end; p += 4) 494 writel(p, u32); 495 } 496 } 497 } 498 499 static void 500 vga_pxlborder_packed(scr_stat *scp, int color) 501 { 502 int i, x, y; 503 int line_width; 504 uint32_t u32; 505 vm_offset_t draw_pos, draw_end, p; 506 507 line_width = scp->sc->adp->va_line_width; 508 u32 = (color << 24) + (color << 16) + (color << 8) + color; 509 510 if (scp->yoff > 0) { 511 draw_pos = scp->sc->adp->va_window; 512 draw_end = draw_pos + line_width * scp->yoff * scp->font_height; 513 514 for (p = draw_pos; p < draw_end; p += 4) 515 writel(p, u32); 516 } 517 518 y = (scp->yoff + scp->ysize) * scp->font_height; 519 520 if (scp->ypixel > y) { 521 draw_pos = scp->sc->adp->va_window + line_width * y; 522 draw_end = draw_pos + line_width * (scp->ypixel - y); 523 524 for (p = draw_pos; p < draw_end; p += 4) 525 writel(p, u32); 526 } 527 528 y = scp->yoff * scp->font_height; 529 x = scp->xpixel / scp->font_width - scp->xoff - scp->xsize; 530 531 for (i = 0; i < scp->ysize * scp->font_height; ++i) { 532 if (scp->xoff > 0) { 533 draw_pos = scp->sc->adp->va_window + 534 line_width * (y + i); 535 draw_end = draw_pos + scp->xoff * scp->font_width; 536 537 for (p = draw_pos; p < draw_end; p += 4) 538 writel(p, u32); 539 } 540 541 if (x > 0) { 542 draw_pos = scp->sc->adp->va_window + 543 line_width * (y + i) + scp->xoff * 8 + 544 scp->xsize * 8; 545 draw_end = draw_pos + x * 8; 546 547 for (p = draw_pos; p < draw_end; p += 4) 548 writel(p, u32); 549 } 550 } 551 } 552 553 static void 554 vga_pxlborder_planar(scr_stat *scp, int color) 555 { 556 vm_offset_t p; 557 int line_width; 558 int x; 559 int y; 560 int i; 561 562 lwkt_gettoken(&tty_token); 563 564 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 565 566 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 567 outw(GDCIDX, 0x0003); /* data rotate/function select */ 568 outw(GDCIDX, 0x0f01); /* set/reset enable */ 569 outw(GDCIDX, 0xff08); /* bit mask */ 570 outw(GDCIDX, (color << 8) | 0x00); /* set/reset */ 571 line_width = scp->sc->adp->va_line_width; 572 p = scp->sc->adp->va_window; 573 if (scp->yoff > 0) 574 bzero_io((void *)p, line_width*scp->yoff*scp->font_height); 575 y = (scp->yoff + scp->ysize)*scp->font_height; 576 if (scp->ypixel > y) 577 bzero_io((void *)(p + line_width*y), 578 line_width*(scp->ypixel - y)); 579 y = scp->yoff*scp->font_height; 580 x = scp->xpixel/scp->font_width - scp->xoff - scp->xsize; 581 for (i = 0; i < scp->ysize*scp->font_height; ++i) { 582 if (scp->xoff > 0) 583 bzero_io((void *)(p + line_width*(y + i)), scp->xoff); 584 if (x > 0) 585 bzero_io((void *)(p + line_width*(y + i) 586 + scp->xoff + scp->xsize), x); 587 } 588 outw(GDCIDX, 0x0000); /* set/reset */ 589 outw(GDCIDX, 0x0001); /* set/reset enable */ 590 lwkt_reltoken(&tty_token); 591 } 592 593 static void 594 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip) 595 { 596 int line_width, pixel_size; 597 int a, i, j, k, l, pos; 598 uint32_t fg, bg, u32; 599 unsigned char *char_data; 600 vm_offset_t draw_pos, p; 601 602 line_width = scp->sc->adp->va_line_width; 603 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 604 605 draw_pos = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size); 606 607 if (from + count > scp->xsize * scp->ysize) 608 count = scp->xsize * scp->ysize - from; 609 610 for (i = from; count-- > 0; ++i) { 611 a = sc_vtb_geta(&scp->vtb, i); 612 613 if (flip) { 614 fg = scp->ega_palette[(((a & 0x7000) >> 4) | 615 (a & 0x0800)) >> 8]; 616 bg = scp->ega_palette[(((a & 0x8000) >> 4) | 617 (a & 0x0700)) >> 8]; 618 } else { 619 fg = scp->ega_palette[(a & 0x0f00) >> 8]; 620 bg = scp->ega_palette[(a & 0xf000) >> 12]; 621 } 622 623 p = draw_pos; 624 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 625 scp->font_height]); 626 627 for (j = 0; j < scp->font_height; ++j, ++char_data) { 628 pos = 7; 629 630 for (k = 0; k < 2 * pixel_size; ++k) { 631 u32 = 0; 632 633 for (l = 0; l < 4 / pixel_size; ++l) { 634 u32 += (*char_data & (1 << pos--) ? 635 fg : bg) << (l * 8 * pixel_size); 636 } 637 638 writel(p, u32); 639 p += 4; 640 } 641 642 p += line_width - 8 * pixel_size; 643 } 644 645 draw_pos += 8 * pixel_size; 646 647 if ((i % scp->xsize) == scp->xsize - 1) 648 draw_pos += scp->xoff * 16 * pixel_size + 649 (scp->font_height - 1) * line_width; 650 } 651 } 652 653 static void 654 vga_vgadraw_packed(scr_stat *scp, int from, int count, int flip) 655 { 656 int line_width; 657 int a, i, j; 658 uint32_t fg, bg, u32; 659 unsigned char *char_data; 660 vm_offset_t draw_pos, p; 661 662 line_width = scp->sc->adp->va_line_width; 663 664 draw_pos = VIDEO_MEMORY_POS(scp, from, 8); 665 666 if (from + count > scp->xsize * scp->ysize) 667 count = scp->xsize * scp->ysize - from; 668 669 for (i = from; count-- > 0; ++i) { 670 a = sc_vtb_geta(&scp->vtb, i); 671 672 if (flip) { 673 fg = ((a & 0xf000) >> 4) >> 8; 674 bg = (a & 0x0f00) >> 8; 675 } else { 676 fg = (a & 0x0f00) >> 8; 677 bg = ((a & 0xf000) >> 4) >> 8; 678 } 679 680 p = draw_pos; 681 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 682 scp->font_height]); 683 684 for (j = 0; j < scp->font_height; ++j, ++char_data) { 685 u32 = ((*char_data & 1 ? fg : bg) << 24) + 686 ((*char_data & 2 ? fg : bg) << 16) + 687 ((*char_data & 4 ? fg : bg) << 8) + 688 (*char_data & 8 ? fg : bg); 689 writel(p + 4, u32); 690 691 u32 = ((*char_data & 16 ? fg : bg) << 24) + 692 ((*char_data & 32 ? fg : bg) << 16) + 693 ((*char_data & 64 ? fg : bg) << 8) + 694 (*char_data & 128 ? fg : bg); 695 writel(p, u32); 696 697 p += line_width; 698 } 699 700 draw_pos += scp->font_width; 701 702 if ((i % scp->xsize) == scp->xsize - 1) 703 draw_pos += scp->xoff * 16 + 704 (scp->font_height - 1) * line_width; 705 } 706 } 707 708 static void 709 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip) 710 { 711 vm_offset_t d; 712 vm_offset_t e; 713 u_char *f; 714 u_short bg; 715 u_short col1, col2; 716 int line_width; 717 int i, j; 718 int a; 719 u_char c; 720 721 d = VIDEO_MEMORY_POS(scp, from, 1); 722 723 line_width = scp->sc->adp->va_line_width; 724 725 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 726 outw(GDCIDX, 0x0003); /* data rotate/function select */ 727 outw(GDCIDX, 0x0f01); /* set/reset enable */ 728 outw(GDCIDX, 0xff08); /* bit mask */ 729 bg = -1; 730 if (from + count > scp->xsize*scp->ysize) 731 count = scp->xsize*scp->ysize - from; 732 for (i = from; count-- > 0; ++i) { 733 a = sc_vtb_geta(&scp->vtb, i); 734 if (flip) { 735 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 736 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 737 } else { 738 col1 = (a & 0x0f00); 739 col2 = (a & 0xf000) >> 4; 740 } 741 /* set background color in EGA/VGA latch */ 742 if (bg != col2) { 743 bg = col2; 744 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 745 outw(GDCIDX, bg | 0x00); /* set/reset */ 746 writeb(d, 0); 747 c = readb(d); /* set bg color in the latch */ 748 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 749 } 750 /* foreground color */ 751 outw(GDCIDX, col1 | 0x00); /* set/reset */ 752 e = d; 753 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_height]); 754 for (j = 0; j < scp->font_height; ++j, ++f) { 755 writeb(e, *f); 756 e += line_width; 757 } 758 ++d; 759 if ((i % scp->xsize) == scp->xsize - 1) 760 d += scp->xoff*2 761 + (scp->font_height - 1)*line_width; 762 } 763 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 764 outw(GDCIDX, 0x0000); /* set/reset */ 765 outw(GDCIDX, 0x0001); /* set/reset enable */ 766 } 767 768 static void 769 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink) 770 { 771 if (base < 0 || base >= scp->font_height) 772 return; 773 /* the caller may set height <= 0 in order to disable the cursor */ 774 #if 0 775 scp->cursor_base = base; 776 scp->cursor_height = height; 777 #endif 778 } 779 780 static void 781 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip) 782 { 783 int line_width, pixel_size, height; 784 int a, i, j, k, pos; 785 uint32_t fg, bg, u32; 786 unsigned char *char_data; 787 vm_offset_t draw_pos; 788 789 line_width = scp->sc->adp->va_line_width; 790 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 791 792 draw_pos = VIDEO_MEMORY_POS(scp, at, scp->font_width * pixel_size) + 793 (scp->font_height - scp->cursor_base - 1) * line_width; 794 795 a = sc_vtb_geta(&scp->vtb, at); 796 797 if (flip) { 798 fg = scp->ega_palette[((on) ? (a & 0x0f00) : 799 ((a & 0xf000) >> 4)) >> 8]; 800 bg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 801 (a & 0x0f00)) >> 8]; 802 } else { 803 fg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 804 (a & 0x0f00)) >> 8]; 805 bg = scp->ega_palette[((on) ? (a & 0x0f00) : 806 ((a & 0xf000) >> 4)) >> 8]; 807 } 808 809 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_height + 810 scp->font_height - scp->cursor_base - 1]); 811 812 height = imin(scp->cursor_height, scp->font_height); 813 814 for (i = 0; i < height; ++i, --char_data) { 815 pos = 7; 816 817 for (j = 0; j < 2 * pixel_size; ++j) { 818 u32 = 0; 819 820 for (k = 0; k < 4 / pixel_size; ++k) { 821 u32 += (*char_data & (1 << pos--) ? 822 fg : bg) << (k * 8 * pixel_size); 823 } 824 825 writel(draw_pos, u32); 826 draw_pos += 4; 827 } 828 829 draw_pos -= line_width + 8 * pixel_size; 830 } 831 } 832 833 static void 834 draw_pxlcursor_packed(scr_stat *scp, int at, int on, int flip) 835 { 836 int line_width, height; 837 int a, i; 838 uint32_t fg, bg, u32; 839 unsigned char *char_data; 840 vm_offset_t draw_pos; 841 842 line_width = scp->sc->adp->va_line_width; 843 844 draw_pos = VIDEO_MEMORY_POS(scp, at, 8) + 845 (scp->font_height - scp->cursor_base - 1) * line_width; 846 847 a = sc_vtb_geta(&scp->vtb, at); 848 849 if (flip) { 850 fg = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8; 851 bg = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8; 852 } else { 853 fg = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8; 854 bg = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8; 855 } 856 857 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_height + 858 scp->font_height - scp->cursor_base - 1]); 859 860 height = imin(scp->cursor_height, scp->font_height); 861 862 for (i = 0; i < height; ++i, --char_data) { 863 u32 = ((*char_data & 1 ? fg : bg) << 24) + 864 ((*char_data & 2 ? fg : bg) << 16) + 865 ((*char_data & 4 ? fg : bg) << 8) + 866 (*char_data & 8 ? fg : bg); 867 writel(draw_pos + 4, u32); 868 869 u32 = ((*char_data & 16 ? fg : bg) << 24) + 870 ((*char_data & 32 ? fg : bg) << 16) + 871 ((*char_data & 64 ? fg : bg) << 8) + 872 (*char_data & 128 ? fg : bg); 873 writel(draw_pos, u32); 874 875 draw_pos -= line_width; 876 } 877 } 878 879 static void 880 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip) 881 { 882 vm_offset_t d; 883 u_char *f; 884 int line_width; 885 int height; 886 int col; 887 int a; 888 int i; 889 u_char c; 890 891 line_width = scp->sc->adp->va_line_width; 892 893 d = VIDEO_MEMORY_POS(scp, at, 1) + 894 (scp->font_height - scp->cursor_base - 1) * line_width; 895 896 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 897 outw(GDCIDX, 0x0003); /* data rotate/function select */ 898 outw(GDCIDX, 0x0f01); /* set/reset enable */ 899 /* set background color in EGA/VGA latch */ 900 a = sc_vtb_geta(&scp->vtb, at); 901 if (flip) 902 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 903 else 904 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 905 outw(GDCIDX, col | 0x00); /* set/reset */ 906 outw(GDCIDX, 0xff08); /* bit mask */ 907 writeb(d, 0); 908 c = readb(d); /* set bg color in the latch */ 909 /* foreground color */ 910 if (flip) 911 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 912 else 913 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 914 outw(GDCIDX, col | 0x00); /* set/reset */ 915 f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_height 916 + scp->font_height - scp->cursor_base - 1]); 917 height = imin(scp->cursor_height, scp->font_height); 918 for (i = 0; i < height; ++i, --f) { 919 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 920 writeb(d, 0); 921 d -= line_width; 922 } 923 outw(GDCIDX, 0x0000); /* set/reset */ 924 outw(GDCIDX, 0x0001); /* set/reset enable */ 925 outw(GDCIDX, 0xff08); /* bit mask */ 926 } 927 928 static int pxlblinkrate = 0; 929 930 static void 931 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip) 932 { 933 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 934 return; 935 936 if (on) { 937 if (!blink) { 938 scp->status |= VR_CURSOR_ON; 939 draw_pxlcursor_direct(scp, at, on, flip); 940 } else if (++pxlblinkrate & 4) { 941 pxlblinkrate = 0; 942 scp->status ^= VR_CURSOR_ON; 943 draw_pxlcursor_direct(scp, at, 944 scp->status & VR_CURSOR_ON, 945 flip); 946 } 947 } else { 948 if (scp->status & VR_CURSOR_ON) 949 draw_pxlcursor_direct(scp, at, on, flip); 950 scp->status &= ~VR_CURSOR_ON; 951 } 952 if (blink) 953 scp->status |= VR_CURSOR_BLINK; 954 else 955 scp->status &= ~VR_CURSOR_BLINK; 956 } 957 958 static void 959 vga_pxlcursor_packed(scr_stat *scp, int at, int blink, int on, int flip) 960 { 961 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 962 return; 963 964 if (on) { 965 if (!blink) { 966 scp->status |= VR_CURSOR_ON; 967 draw_pxlcursor_packed(scp, at, on, flip); 968 } else if (++pxlblinkrate & 4) { 969 pxlblinkrate = 0; 970 scp->status ^= VR_CURSOR_ON; 971 draw_pxlcursor_packed(scp, at, 972 scp->status & VR_CURSOR_ON, 973 flip); 974 } 975 } else { 976 if (scp->status & VR_CURSOR_ON) 977 draw_pxlcursor_packed(scp, at, on, flip); 978 scp->status &= ~VR_CURSOR_ON; 979 } 980 if (blink) 981 scp->status |= VR_CURSOR_BLINK; 982 else 983 scp->status &= ~VR_CURSOR_BLINK; 984 } 985 986 static void 987 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip) 988 { 989 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 990 return; 991 992 if (on) { 993 if (!blink) { 994 scp->status |= VR_CURSOR_ON; 995 draw_pxlcursor_planar(scp, at, on, flip); 996 } else if (++pxlblinkrate & 4) { 997 pxlblinkrate = 0; 998 scp->status ^= VR_CURSOR_ON; 999 draw_pxlcursor_planar(scp, at, 1000 scp->status & VR_CURSOR_ON, 1001 flip); 1002 } 1003 } else { 1004 if (scp->status & VR_CURSOR_ON) 1005 draw_pxlcursor_planar(scp, at, on, flip); 1006 scp->status &= ~VR_CURSOR_ON; 1007 } 1008 if (blink) 1009 scp->status |= VR_CURSOR_BLINK; 1010 else 1011 scp->status &= ~VR_CURSOR_BLINK; 1012 } 1013 1014 static void 1015 vga_pxlblink_direct(scr_stat *scp, int at, int flip) 1016 { 1017 if (!(scp->status & VR_CURSOR_BLINK)) 1018 return; 1019 if (!(++pxlblinkrate & 4)) 1020 return; 1021 pxlblinkrate = 0; 1022 scp->status ^= VR_CURSOR_ON; 1023 draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip); 1024 } 1025 1026 static void 1027 vga_pxlblink_packed(scr_stat *scp, int at, int flip) 1028 { 1029 if (!(scp->status & VR_CURSOR_BLINK)) 1030 return; 1031 if (!(++pxlblinkrate & 4)) 1032 return; 1033 pxlblinkrate = 0; 1034 scp->status ^= VR_CURSOR_ON; 1035 draw_pxlcursor_packed(scp, at, scp->status & VR_CURSOR_ON, flip); 1036 } 1037 1038 static void 1039 vga_pxlblink_planar(scr_stat *scp, int at, int flip) 1040 { 1041 if (!(scp->status & VR_CURSOR_BLINK)) 1042 return; 1043 if (!(++pxlblinkrate & 4)) 1044 return; 1045 pxlblinkrate = 0; 1046 scp->status ^= VR_CURSOR_ON; 1047 draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip); 1048 } 1049 1050 #ifndef SC_NO_CUTPASTE 1051 1052 static void 1053 draw_pxlmouse_direct(scr_stat *scp, int x, int y) 1054 { 1055 int line_width, pixel_size; 1056 int xend, yend; 1057 int i, j; 1058 vm_offset_t draw_pos; 1059 1060 line_width = scp->sc->adp->va_line_width; 1061 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 1062 1063 xend = imin(x + 8, 8 * (scp->xoff + scp->xsize)); 1064 yend = imin(y + 16, scp->font_height * (scp->yoff + scp->ysize)); 1065 1066 draw_pos = scp->sc->adp->va_window + y * line_width + x * pixel_size; 1067 1068 for (i = 0; i < (yend - y); i++) { 1069 for (j = (xend - x - 1); j >= 0; j--) { 1070 switch (scp->sc->adp->va_info.vi_depth) { 1071 case 32: 1072 if (mouse_or_mask[i] & 1 << (15 - j)) 1073 writel(draw_pos + 4 * j, 1074 scp->ega_palette[15]); 1075 else if (mouse_and_mask[i] & 1 << (15 - j)) 1076 writel(draw_pos + 4 * j, 1077 scp->ega_palette[0]); 1078 break; 1079 case 16: 1080 /* FALLTHROUGH */ 1081 case 15: 1082 if (mouse_or_mask[i] & 1 << (15 - j)) 1083 writew(draw_pos + 2 * j, 1084 scp->ega_palette[15]); 1085 else if (mouse_and_mask[i] & 1 << (15 - j)) 1086 writew(draw_pos + 2 * j, 1087 scp->ega_palette[0]); 1088 break; 1089 } 1090 } 1091 1092 draw_pos += line_width; 1093 } 1094 } 1095 1096 static void 1097 draw_pxlmouse_packed(scr_stat *scp, int x, int y) 1098 { 1099 int line_width; 1100 int xend, yend; 1101 int i, j; 1102 vm_offset_t draw_pos; 1103 1104 line_width = scp->sc->adp->va_line_width; 1105 1106 xend = imin(scp->font_width * (scp->xoff + scp->xsize), 1107 imin(x + 16, scp->xpixel)); 1108 yend = imin(scp->font_height * (scp->yoff + scp->ysize), 1109 imin(y + 16, scp->ypixel)); 1110 1111 draw_pos = scp->sc->adp->va_window + y * line_width + x; 1112 1113 for (i = 0; i < (yend - y); i++) { 1114 for (j = (xend - x - 1); j >= 0; j--) { 1115 if (mouse_or_mask[i] & 1 << (15 - j)) 1116 writeb(draw_pos + j, 15); 1117 else if (mouse_and_mask[i] & 1 << (15 - j)) 1118 writeb(draw_pos + j, 0); 1119 } 1120 1121 draw_pos += line_width; 1122 } 1123 } 1124 1125 static void 1126 draw_pxlmouse_planar(scr_stat *scp, int x, int y) 1127 { 1128 vm_offset_t p; 1129 int line_width; 1130 int xoff; 1131 int ymax; 1132 u_short m; 1133 int i, j; 1134 1135 line_width = scp->sc->adp->va_line_width; 1136 xoff = (x - scp->xoff*8)%8; 1137 ymax = imin(y + 16, scp->font_height * (scp->yoff + scp->ysize)); 1138 1139 outw(GDCIDX, 0x0805); /* read mode 1, write mode 0 */ 1140 outw(GDCIDX, 0x0001); /* set/reset enable */ 1141 outw(GDCIDX, 0x0002); /* color compare */ 1142 outw(GDCIDX, 0x0007); /* color don't care */ 1143 outw(GDCIDX, 0xff08); /* bit mask */ 1144 outw(GDCIDX, 0x0803); /* data rotate/function select (and) */ 1145 p = scp->sc->adp->va_window + line_width*y + x/8; 1146 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1147 for (i = y, j = 0; i < ymax; ++i, ++j) { 1148 m = ~(mouse_and_mask[j] >> xoff); 1149 *(u_char *)p &= m >> 8; 1150 *(u_char *)(p + 1) &= m; 1151 p += line_width; 1152 } 1153 } else { 1154 xoff += 8; 1155 for (i = y, j = 0; i < ymax; ++i, ++j) { 1156 m = ~(mouse_and_mask[j] >> xoff); 1157 *(u_char *)p &= m; 1158 p += line_width; 1159 } 1160 } 1161 outw(GDCIDX, 0x1003); /* data rotate/function select (or) */ 1162 p = scp->sc->adp->va_window + line_width*y + x/8; 1163 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1164 for (i = y, j = 0; i < ymax; ++i, ++j) { 1165 m = mouse_or_mask[j] >> xoff; 1166 *(u_char *)p &= m >> 8; 1167 *(u_char *)(p + 1) &= m; 1168 p += line_width; 1169 } 1170 } else { 1171 for (i = y, j = 0; i < ymax; ++i, ++j) { 1172 m = mouse_or_mask[j] >> xoff; 1173 *(u_char *)p &= m; 1174 p += line_width; 1175 } 1176 } 1177 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 1178 outw(GDCIDX, 0x0003); /* data rotate/function select */ 1179 } 1180 1181 static void 1182 remove_pxlmouse(scr_stat *scp, int x, int y) 1183 { 1184 int col, row; 1185 int pos; 1186 int i; 1187 1188 /* erase the mouse cursor image */ 1189 col = x / scp->font_width - scp->xoff; 1190 row = y / scp->font_height - scp->yoff; 1191 pos = row * scp->xsize + col; 1192 i = (col < scp->xsize - 1) ? 2 : 1; 1193 (*scp->rndr->draw)(scp, pos, i, FALSE); 1194 if (row < scp->ysize - 1) 1195 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 1196 } 1197 1198 static void 1199 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on) 1200 { 1201 if (on) 1202 draw_pxlmouse_direct(scp, x, y); 1203 else 1204 remove_pxlmouse(scp, x, y); 1205 } 1206 1207 static void 1208 vga_pxlmouse_packed(scr_stat *scp, int x, int y, int on) 1209 { 1210 if (on) 1211 draw_pxlmouse_packed(scp, x, y); 1212 else 1213 remove_pxlmouse(scp, x, y); 1214 } 1215 1216 static void 1217 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on) 1218 { 1219 if (on) 1220 draw_pxlmouse_planar(scp, x, y); 1221 else 1222 remove_pxlmouse(scp, x, y); 1223 } 1224 1225 #endif /* SC_NO_CUTPASTE */ 1226 #endif /* SC_PIXEL_MODE */ 1227 1228 #ifndef SC_NO_MODE_CHANGE 1229 1230 /* graphics mode renderer */ 1231 1232 static void 1233 vga_grborder(scr_stat *scp, int color) 1234 { 1235 lwkt_gettoken(&tty_token); 1236 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 1237 lwkt_reltoken(&tty_token); 1238 } 1239 1240 #endif 1241