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