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 * $DragonFly: src/sys/dev/misc/syscons/scvgarndr.c,v 1.11 2005/02/18 16:38:23 swildner Exp $ 31 */ 32 33 #include "opt_syscons.h" 34 #include "opt_vga.h" 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.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 #ifndef SC_RENDER_DEBUG 49 #define SC_RENDER_DEBUG 0 50 #endif 51 52 static vr_clear_t vga_txtclear; 53 static vr_draw_border_t vga_txtborder; 54 static vr_draw_t vga_txtdraw; 55 static vr_set_cursor_t vga_txtcursor_shape; 56 static vr_draw_cursor_t vga_txtcursor; 57 static vr_blink_cursor_t vga_txtblink; 58 #ifndef SC_NO_CUTPASTE 59 static vr_draw_mouse_t vga_txtmouse; 60 #else 61 #define vga_txtmouse (vr_draw_mouse_t *)vga_nop 62 #endif 63 64 #ifdef SC_PIXEL_MODE 65 static vr_init_t vga_rndrinit; 66 static vr_clear_t vga_pxlclear_direct; 67 static vr_clear_t vga_pxlclear_planar; 68 static vr_draw_border_t vga_pxlborder_direct; 69 static vr_draw_border_t vga_pxlborder_planar; 70 static vr_draw_t vga_egadraw; 71 static vr_draw_t vga_vgadraw_direct; 72 static vr_draw_t vga_vgadraw_planar; 73 static vr_set_cursor_t vga_pxlcursor_shape; 74 static vr_draw_cursor_t vga_pxlcursor_direct; 75 static vr_draw_cursor_t vga_pxlcursor_planar; 76 static vr_blink_cursor_t vga_pxlblink_direct; 77 static vr_blink_cursor_t vga_pxlblink_planar; 78 #ifndef SC_NO_CUTPASTE 79 static vr_draw_mouse_t vga_pxlmouse_direct; 80 static vr_draw_mouse_t vga_pxlmouse_planar; 81 #else 82 #define vga_pxlmouse_direct (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 (vr_init_t *)vga_nop, 95 vga_txtclear, 96 vga_txtborder, 97 vga_txtdraw, 98 vga_txtcursor_shape, 99 vga_txtcursor, 100 vga_txtblink, 101 (vr_set_mouse_t *)vga_nop, 102 vga_txtmouse, 103 }; 104 RENDERER(mda, 0, txtrndrsw, vga_set); 105 RENDERER(cga, 0, txtrndrsw, vga_set); 106 RENDERER(ega, 0, txtrndrsw, vga_set); 107 RENDERER(vga, 0, txtrndrsw, vga_set); 108 109 #ifdef SC_PIXEL_MODE 110 static sc_rndr_sw_t egarndrsw = { 111 (vr_init_t *)vga_nop, 112 vga_pxlclear_planar, 113 vga_pxlborder_planar, 114 vga_egadraw, 115 vga_pxlcursor_shape, 116 vga_pxlcursor_planar, 117 vga_pxlblink_planar, 118 (vr_set_mouse_t *)vga_nop, 119 vga_pxlmouse_planar, 120 }; 121 RENDERER(ega, PIXEL_MODE, egarndrsw, vga_set); 122 123 static sc_rndr_sw_t vgarndrsw = { 124 vga_rndrinit, 125 (vr_clear_t *)vga_nop, 126 (vr_draw_border_t *)vga_nop, 127 (vr_draw_t *)vga_nop, 128 vga_pxlcursor_shape, 129 (vr_draw_cursor_t *)vga_nop, 130 (vr_blink_cursor_t *)vga_nop, 131 (vr_set_mouse_t *)vga_nop, 132 (vr_draw_mouse_t *)vga_nop, 133 }; 134 RENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set); 135 #endif /* SC_PIXEL_MODE */ 136 137 #ifndef SC_NO_MODE_CHANGE 138 static sc_rndr_sw_t grrndrsw = { 139 (vr_init_t *)vga_nop, 140 (vr_clear_t *)vga_nop, 141 vga_grborder, 142 (vr_draw_t *)vga_nop, 143 (vr_set_cursor_t *)vga_nop, 144 (vr_draw_cursor_t *)vga_nop, 145 (vr_blink_cursor_t *)vga_nop, 146 (vr_set_mouse_t *)vga_nop, 147 (vr_draw_mouse_t *)vga_nop, 148 }; 149 RENDERER(cga, GRAPHICS_MODE, grrndrsw, vga_set); 150 RENDERER(ega, GRAPHICS_MODE, grrndrsw, vga_set); 151 RENDERER(vga, GRAPHICS_MODE, grrndrsw, vga_set); 152 #endif /* SC_NO_MODE_CHANGE */ 153 154 RENDERER_MODULE(vga, vga_set); 155 156 #ifndef SC_NO_CUTPASTE 157 static u_short mouse_and_mask[16] = { 158 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 159 0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000 160 }; 161 static u_short mouse_or_mask[16] = { 162 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800, 163 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000 164 }; 165 #endif 166 167 static void 168 vga_nop(scr_stat *scp, ...) 169 { 170 } 171 172 /* text mode renderer */ 173 174 static void 175 vga_txtclear(scr_stat *scp, int c, int attr) 176 { 177 sc_vtb_clear(&scp->scr, c, attr); 178 } 179 180 static void 181 vga_txtborder(scr_stat *scp, int color) 182 { 183 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 184 } 185 186 static void 187 vga_txtdraw(scr_stat *scp, int from, int count, int flip) 188 { 189 vm_offset_t p; 190 int c; 191 int a; 192 193 if (from + count > scp->xsize*scp->ysize) 194 count = scp->xsize*scp->ysize - from; 195 196 if (flip) { 197 for (p = sc_vtb_pointer(&scp->scr, from); count-- > 0; ++from) { 198 c = sc_vtb_getc(&scp->vtb, from); 199 a = sc_vtb_geta(&scp->vtb, from); 200 a = (a & 0x8800) | ((a & 0x7000) >> 4) 201 | ((a & 0x0700) << 4); 202 p = sc_vtb_putchar(&scp->scr, p, c, a); 203 } 204 } else { 205 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count); 206 } 207 } 208 209 static void 210 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink) 211 { 212 if (base < 0 || base >= scp->font_size) 213 return; 214 /* the caller may set height <= 0 in order to disable the cursor */ 215 #if 0 216 scp->cursor_base = base; 217 scp->cursor_height = height; 218 #endif 219 (*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp, 220 base, height, 221 scp->font_size, blink); 222 } 223 224 static void 225 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip) 226 { 227 sc_softc_t *sc; 228 229 sc = scp->sc; 230 scp->cursor_saveunder_char = c; 231 scp->cursor_saveunder_attr = a; 232 233 #ifndef SC_NO_FONT_LOADING 234 if (sc->flags & SC_CHAR_CURSOR) { 235 unsigned char *font; 236 int h; 237 int i; 238 239 if (scp->font_size < 14) { 240 font = sc->font_8; 241 h = 8; 242 } else if (scp->font_size >= 16) { 243 font = sc->font_16; 244 h = 16; 245 } else { 246 font = sc->font_14; 247 h = 14; 248 } 249 if (scp->cursor_base >= h) 250 return; 251 if (flip) 252 a = (a & 0x8800) 253 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 254 bcopy(font + c*h, font + sc->cursor_char*h, h); 255 font = font + sc->cursor_char*h; 256 for (i = imax(h - scp->cursor_base - scp->cursor_height, 0); 257 i < h - scp->cursor_base; ++i) { 258 font[i] ^= 0xff; 259 } 260 sc->font_loading_in_progress = TRUE; 261 /* XXX */ 262 (*vidsw[sc->adapter]->load_font)(sc->adp, 0, h, font, 263 sc->cursor_char, 1); 264 sc->font_loading_in_progress = FALSE; 265 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a); 266 } else 267 #endif /* SC_NO_FONT_LOADING */ 268 { 269 if ((a & 0x7000) == 0x7000) { 270 a &= 0x8f00; 271 if ((a & 0x0700) == 0) 272 a |= 0x0700; 273 } else { 274 a |= 0x7000; 275 if ((a & 0x0700) == 0x0700) 276 a &= 0xf000; 277 } 278 if (flip) 279 a = (a & 0x8800) 280 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 281 sc_vtb_putc(&scp->scr, at, c, a); 282 } 283 } 284 285 static void 286 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip) 287 { 288 video_adapter_t *adp; 289 int cursor_attr; 290 291 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 292 return; 293 294 adp = scp->sc->adp; 295 if (blink) { 296 scp->status |= VR_CURSOR_BLINK; 297 if (on) { 298 scp->status |= VR_CURSOR_ON; 299 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 300 at%scp->xsize, 301 at/scp->xsize); 302 } else { 303 if (scp->status & VR_CURSOR_ON) 304 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 305 -1, -1); 306 scp->status &= ~VR_CURSOR_ON; 307 } 308 } else { 309 scp->status &= ~VR_CURSOR_BLINK; 310 if (on) { 311 scp->status |= VR_CURSOR_ON; 312 draw_txtcharcursor(scp, at, 313 sc_vtb_getc(&scp->scr, at), 314 sc_vtb_geta(&scp->scr, at), 315 flip); 316 } else { 317 cursor_attr = scp->cursor_saveunder_attr; 318 if (flip) 319 cursor_attr = (cursor_attr & 0x8800) 320 | ((cursor_attr & 0x7000) >> 4) 321 | ((cursor_attr & 0x0700) << 4); 322 if (scp->status & VR_CURSOR_ON) 323 sc_vtb_putc(&scp->scr, at, 324 scp->cursor_saveunder_char, 325 cursor_attr); 326 scp->status &= ~VR_CURSOR_ON; 327 } 328 } 329 } 330 331 static void 332 vga_txtblink(scr_stat *scp, int at, int flip) 333 { 334 } 335 336 #ifndef SC_NO_CUTPASTE 337 338 static void 339 draw_txtmouse(scr_stat *scp, int x, int y) 340 { 341 #ifndef SC_ALT_MOUSE_IMAGE 342 if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) { 343 u_char font_buf[128]; 344 u_short cursor[32]; 345 u_char c; 346 int pos; 347 int xoffset, yoffset; 348 int crtc_addr; 349 int i; 350 351 /* prepare mousepointer char's bitmaps */ 352 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 353 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size, 354 &font_buf[0], scp->font_size); 355 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size, 356 &font_buf[32], scp->font_size); 357 bcopy(scp->font 358 + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size, 359 &font_buf[64], scp->font_size); 360 bcopy(scp->font 361 + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size, 362 &font_buf[96], scp->font_size); 363 for (i = 0; i < scp->font_size; ++i) { 364 cursor[i] = font_buf[i]<<8 | font_buf[i+32]; 365 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96]; 366 } 367 368 /* now and-or in the mousepointer image */ 369 xoffset = x%8; 370 yoffset = y%scp->font_size; 371 for (i = 0; i < 16; ++i) { 372 cursor[i + yoffset] = 373 (cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset)) 374 | (mouse_or_mask[i] >> xoffset); 375 } 376 for (i = 0; i < scp->font_size; ++i) { 377 font_buf[i] = (cursor[i] & 0xff00) >> 8; 378 font_buf[i + 32] = cursor[i] & 0xff; 379 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8; 380 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff; 381 } 382 383 #if 1 384 /* wait for vertical retrace to avoid jitter on some videocards */ 385 crtc_addr = scp->sc->adp->va_crtc_addr; 386 while (!(inb(crtc_addr + 6) & 0x08)) /* idle */ ; 387 #endif 388 c = scp->sc->mouse_char; 389 (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf, 390 c, 4); 391 392 sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos)); 393 /* FIXME: may be out of range! */ 394 sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2, 395 sc_vtb_geta(&scp->scr, pos + scp->xsize)); 396 if (x < (scp->xsize - 1)*8) { 397 sc_vtb_putc(&scp->scr, pos + 1, c + 1, 398 sc_vtb_geta(&scp->scr, pos + 1)); 399 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3, 400 sc_vtb_geta(&scp->scr, pos + scp->xsize + 1)); 401 } 402 } else 403 #endif /* SC_ALT_MOUSE_IMAGE */ 404 { 405 /* Red, magenta and brown are mapped to green to to keep it readable */ 406 static const int col_conv[16] = { 407 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14 408 }; 409 int pos; 410 int color; 411 int a; 412 413 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 414 a = sc_vtb_geta(&scp->scr, pos); 415 if (scp->sc->adp->va_flags & V_ADP_COLOR) 416 color = (col_conv[(a & 0xf000) >> 12] << 12) 417 | ((a & 0x0f00) | 0x0800); 418 else 419 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4); 420 sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color); 421 } 422 } 423 424 static void 425 remove_txtmouse(scr_stat *scp, int x, int y) 426 { 427 } 428 429 static void 430 vga_txtmouse(scr_stat *scp, int x, int y, int on) 431 { 432 if (on) 433 draw_txtmouse(scp, x, y); 434 else 435 remove_txtmouse(scp, x, y); 436 } 437 438 #endif /* SC_NO_CUTPASTE */ 439 440 #ifdef SC_PIXEL_MODE 441 442 /* pixel (raster text) mode renderer */ 443 444 static void 445 vga_rndrinit(scr_stat *scp) 446 { 447 if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PLANAR) { 448 scp->rndr->clear = vga_pxlclear_planar; 449 scp->rndr->draw_border = vga_pxlborder_planar; 450 scp->rndr->draw = vga_vgadraw_planar; 451 scp->rndr->draw_cursor = vga_pxlcursor_planar; 452 scp->rndr->blink_cursor = vga_pxlblink_planar; 453 scp->rndr->draw_mouse = vga_pxlmouse_planar; 454 } else if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_DIRECT) { 455 scp->rndr->clear = vga_pxlclear_direct; 456 scp->rndr->draw_border = vga_pxlborder_direct; 457 scp->rndr->draw = vga_vgadraw_direct; 458 scp->rndr->draw_cursor = vga_pxlcursor_direct; 459 scp->rndr->blink_cursor = vga_pxlblink_direct; 460 scp->rndr->draw_mouse = vga_pxlmouse_direct; 461 } 462 } 463 464 static void 465 vga_pxlclear_direct(scr_stat *scp, int c, int attr) 466 { 467 vm_offset_t p; 468 int line_width; 469 int pixel_size; 470 int lines; 471 int i; 472 473 line_width = scp->sc->adp->va_line_width; 474 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 475 lines = scp->ysize * scp->font_size; 476 p = scp->sc->adp->va_window + 477 line_width * scp->yoff * scp->font_size + 478 scp->xoff * 8 * pixel_size; 479 480 for (i = 0; i < lines; ++i) { 481 bzero_io((void *)p, scp->xsize * 8 * pixel_size); 482 p += line_width; 483 } 484 } 485 486 static void 487 vga_pxlclear_planar(scr_stat *scp, int c, int attr) 488 { 489 vm_offset_t p; 490 int line_width; 491 int lines; 492 int i; 493 494 /* XXX: we are just filling the screen with the background color... */ 495 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 496 outw(GDCIDX, 0x0003); /* data rotate/function select */ 497 outw(GDCIDX, 0x0f01); /* set/reset enable */ 498 outw(GDCIDX, 0xff08); /* bit mask */ 499 outw(GDCIDX, ((attr & 0xf000) >> 4) | 0x00); /* set/reset */ 500 line_width = scp->sc->adp->va_line_width; 501 lines = scp->ysize*scp->font_size; 502 p = scp->sc->adp->va_window + line_width*scp->yoff*scp->font_size 503 + scp->xoff; 504 for (i = 0; i < lines; ++i) { 505 bzero_io((void *)p, scp->xsize); 506 p += line_width; 507 } 508 outw(GDCIDX, 0x0000); /* set/reset */ 509 outw(GDCIDX, 0x0001); /* set/reset enable */ 510 } 511 512 static void 513 vga_pxlborder_direct(scr_stat *scp, int color) 514 { 515 int i, x, y; 516 int line_width, pixel_size; 517 uint32_t u32 = 0; 518 vm_offset_t draw_pos, draw_end, p; 519 520 line_width = scp->sc->adp->va_line_width; 521 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 522 523 for (i = 0; i < 4 / pixel_size; ++i) 524 u32 += scp->ega_palette[color] << (i * 8 * pixel_size); 525 526 if (scp->yoff > 0) { 527 draw_pos = scp->sc->adp->va_window; 528 draw_end = draw_pos + 529 line_width * scp->yoff * scp->font_size; 530 531 for (p = draw_pos; p < draw_end; p += 4) 532 writel(p, u32); 533 } 534 535 y = (scp->yoff + scp->ysize) * scp->font_size; 536 537 if (scp->ypixel > y) { 538 draw_pos = scp->sc->adp->va_window + line_width * y; 539 draw_end = draw_pos + line_width * (scp->ypixel - y); 540 541 for (p = draw_pos; p < draw_end; p += 4) 542 writel(p, u32); 543 } 544 545 y = scp->yoff * scp->font_size; 546 x = scp->xpixel / 8 - scp->xoff - scp->xsize; 547 548 for (i = 0; i < scp->ysize * scp->font_size; ++i) { 549 if (scp->xoff > 0) { 550 draw_pos = scp->sc->adp->va_window + 551 line_width * (y + i); 552 draw_end = draw_pos + scp->xoff * 8 * pixel_size; 553 554 for (p = draw_pos; p < draw_end; p += 4) 555 writel(p, u32); 556 } 557 558 if (x > 0) { 559 draw_pos = scp->sc->adp->va_window + 560 line_width * (y + i) + 561 scp->xoff * 8 * pixel_size + 562 scp->xsize * 8 * pixel_size; 563 draw_end = draw_pos + x * 8 * pixel_size; 564 565 for (p = draw_pos; p < draw_end; p += 4) 566 writel(p, u32); 567 } 568 } 569 } 570 571 static void 572 vga_pxlborder_planar(scr_stat *scp, int color) 573 { 574 vm_offset_t p; 575 int line_width; 576 int x; 577 int y; 578 int i; 579 580 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 581 582 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 583 outw(GDCIDX, 0x0003); /* data rotate/function select */ 584 outw(GDCIDX, 0x0f01); /* set/reset enable */ 585 outw(GDCIDX, 0xff08); /* bit mask */ 586 outw(GDCIDX, (color << 8) | 0x00); /* set/reset */ 587 line_width = scp->sc->adp->va_line_width; 588 p = scp->sc->adp->va_window; 589 if (scp->yoff > 0) 590 bzero_io((void *)p, line_width*scp->yoff*scp->font_size); 591 y = (scp->yoff + scp->ysize)*scp->font_size; 592 if (scp->ypixel > y) 593 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y)); 594 y = scp->yoff*scp->font_size; 595 x = scp->xpixel/8 - scp->xoff - scp->xsize; 596 for (i = 0; i < scp->ysize*scp->font_size; ++i) { 597 if (scp->xoff > 0) 598 bzero_io((void *)(p + line_width*(y + i)), scp->xoff); 599 if (x > 0) 600 bzero_io((void *)(p + line_width*(y + i) 601 + scp->xoff + scp->xsize), x); 602 } 603 outw(GDCIDX, 0x0000); /* set/reset */ 604 outw(GDCIDX, 0x0001); /* set/reset enable */ 605 } 606 607 static void 608 vga_egadraw(scr_stat *scp, int from, int count, int flip) 609 { 610 vm_offset_t d; 611 vm_offset_t e; 612 u_char *f; 613 u_short bg; 614 u_short col1, col2; 615 int line_width; 616 int i, j; 617 int a; 618 u_char c; 619 620 line_width = scp->sc->adp->va_line_width; 621 622 d = VIDEO_MEMORY_POS(scp, from, 1); 623 624 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 625 outw(GDCIDX, 0x0003); /* data rotate/function select */ 626 outw(GDCIDX, 0x0f01); /* set/reset enable */ 627 bg = -1; 628 if (from + count > scp->xsize*scp->ysize) 629 count = scp->xsize*scp->ysize - from; 630 for (i = from; count-- > 0; ++i) { 631 a = sc_vtb_geta(&scp->vtb, i); 632 if (flip) { 633 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 634 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 635 } else { 636 col1 = (a & 0x0f00); 637 col2 = (a & 0xf000) >> 4; 638 } 639 /* set background color in EGA/VGA latch */ 640 if (bg != col2) { 641 bg = col2; 642 outw(GDCIDX, bg | 0x00); /* set/reset */ 643 outw(GDCIDX, 0xff08); /* bit mask */ 644 writeb(d, 0); 645 c = readb(d); /* set bg color in the latch */ 646 } 647 /* foreground color */ 648 outw(GDCIDX, col1 | 0x00); /* set/reset */ 649 e = d; 650 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]); 651 for (j = 0; j < scp->font_size; ++j, ++f) { 652 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 653 writeb(e, 0); 654 e += line_width; 655 } 656 ++d; 657 if ((i % scp->xsize) == scp->xsize - 1) 658 d += scp->xoff*2 659 + (scp->font_size - 1)*line_width; 660 } 661 outw(GDCIDX, 0x0000); /* set/reset */ 662 outw(GDCIDX, 0x0001); /* set/reset enable */ 663 outw(GDCIDX, 0xff08); /* bit mask */ 664 } 665 666 static void 667 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip) 668 { 669 int line_width, pixel_size; 670 int a, i, j, k, l, pos; 671 uint32_t fg, bg, u32; 672 unsigned char *char_data; 673 vm_offset_t draw_pos, p; 674 675 line_width = scp->sc->adp->va_line_width; 676 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 677 678 draw_pos = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size); 679 680 if (from + count > scp->xsize * scp->ysize) 681 count = scp->xsize * scp->ysize - from; 682 683 for (i = from; count-- > 0; ++i) { 684 a = sc_vtb_geta(&scp->vtb, i); 685 686 if (flip) { 687 fg = scp->ega_palette[(((a & 0x7000) >> 4) | 688 (a & 0x0800)) >> 8]; 689 bg = scp->ega_palette[(((a & 0x8000) >> 4) | 690 (a & 0x0700)) >> 8]; 691 } else { 692 fg = scp->ega_palette[(a & 0x0f00) >> 8]; 693 bg = scp->ega_palette[(a & 0xf000) >> 12]; 694 } 695 696 p = draw_pos; 697 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 698 scp->font_size]); 699 700 for (j = 0; j < scp->font_size; ++j, ++char_data) { 701 pos = 7; 702 703 for (k = 0; k < 2 * pixel_size; ++k) { 704 u32 = 0; 705 706 for (l = 0; l < 4 / pixel_size; ++l) { 707 u32 += (*char_data & (1 << pos--) ? 708 fg : bg) << (l * 8 * pixel_size); 709 } 710 711 writel(p, u32); 712 p += 4; 713 } 714 715 p += line_width - 8 * pixel_size; 716 } 717 718 draw_pos += 8 * pixel_size; 719 720 if ((i % scp->xsize) == scp->xsize - 1) 721 draw_pos += scp->xoff * 16 * pixel_size + 722 (scp->font_size - 1) * line_width; 723 } 724 } 725 726 static void 727 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip) 728 { 729 vm_offset_t d; 730 vm_offset_t e; 731 u_char *f; 732 u_short bg; 733 u_short col1, col2; 734 int line_width; 735 int i, j; 736 int a; 737 u_char c; 738 739 d = VIDEO_MEMORY_POS(scp, from, 1); 740 741 line_width = scp->sc->adp->va_line_width; 742 743 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 744 outw(GDCIDX, 0x0003); /* data rotate/function select */ 745 outw(GDCIDX, 0x0f01); /* set/reset enable */ 746 outw(GDCIDX, 0xff08); /* bit mask */ 747 bg = -1; 748 if (from + count > scp->xsize*scp->ysize) 749 count = scp->xsize*scp->ysize - from; 750 for (i = from; count-- > 0; ++i) { 751 a = sc_vtb_geta(&scp->vtb, i); 752 if (flip) { 753 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 754 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 755 } else { 756 col1 = (a & 0x0f00); 757 col2 = (a & 0xf000) >> 4; 758 } 759 /* set background color in EGA/VGA latch */ 760 if (bg != col2) { 761 bg = col2; 762 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 763 outw(GDCIDX, bg | 0x00); /* set/reset */ 764 writeb(d, 0); 765 c = readb(d); /* set bg color in the latch */ 766 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 767 } 768 /* foreground color */ 769 outw(GDCIDX, col1 | 0x00); /* set/reset */ 770 e = d; 771 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]); 772 for (j = 0; j < scp->font_size; ++j, ++f) { 773 writeb(e, *f); 774 e += line_width; 775 } 776 ++d; 777 if ((i % scp->xsize) == scp->xsize - 1) 778 d += scp->xoff*2 779 + (scp->font_size - 1)*line_width; 780 } 781 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 782 outw(GDCIDX, 0x0000); /* set/reset */ 783 outw(GDCIDX, 0x0001); /* set/reset enable */ 784 } 785 786 static void 787 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink) 788 { 789 if (base < 0 || base >= scp->font_size) 790 return; 791 /* the caller may set height <= 0 in order to disable the cursor */ 792 #if 0 793 scp->cursor_base = base; 794 scp->cursor_height = height; 795 #endif 796 } 797 798 static void 799 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip) 800 { 801 int line_width, pixel_size, height; 802 int a, i, j, k, pos; 803 uint32_t fg, bg, u32; 804 unsigned char *char_data; 805 vm_offset_t draw_pos; 806 807 line_width = scp->sc->adp->va_line_width; 808 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 809 810 draw_pos = VIDEO_MEMORY_POS(scp, at, 8 * pixel_size) + 811 (scp->font_size - scp->cursor_base - 1) * line_width; 812 813 a = sc_vtb_geta(&scp->vtb, at); 814 815 if (flip) { 816 fg = scp->ega_palette[((on) ? (a & 0x0f00) : 817 ((a & 0xf000) >> 4)) >> 8]; 818 bg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 819 (a & 0x0f00)) >> 8]; 820 } else { 821 fg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 822 (a & 0x0f00)) >> 8]; 823 bg = scp->ega_palette[((on) ? (a & 0x0f00) : 824 ((a & 0xf000) >> 4)) >> 8]; 825 } 826 827 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size + 828 scp->font_size - scp->cursor_base - 1]); 829 830 height = imin(scp->cursor_height, scp->font_size); 831 832 for (i = 0; i < height; ++i, --char_data) { 833 pos = 7; 834 835 for (j = 0; j < 2 * pixel_size; ++j) { 836 u32 = 0; 837 838 for (k = 0; k < 4 / pixel_size; ++k) { 839 u32 += (*char_data & (1 << pos--) ? 840 fg : bg) << (k * 8 * pixel_size); 841 } 842 843 writel(draw_pos, u32); 844 draw_pos += 4; 845 } 846 847 draw_pos -= line_width + 8 * pixel_size; 848 } 849 } 850 851 static void 852 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip) 853 { 854 vm_offset_t d; 855 u_char *f; 856 int line_width; 857 int height; 858 int col; 859 int a; 860 int i; 861 u_char c; 862 863 line_width = scp->sc->adp->va_line_width; 864 865 d = VIDEO_MEMORY_POS(scp, at, 1) + 866 (scp->font_size - scp->cursor_base - 1) * line_width; 867 868 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 869 outw(GDCIDX, 0x0003); /* data rotate/function select */ 870 outw(GDCIDX, 0x0f01); /* set/reset enable */ 871 /* set background color in EGA/VGA latch */ 872 a = sc_vtb_geta(&scp->vtb, at); 873 if (flip) 874 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 875 else 876 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 877 outw(GDCIDX, col | 0x00); /* set/reset */ 878 outw(GDCIDX, 0xff08); /* bit mask */ 879 writeb(d, 0); 880 c = readb(d); /* set bg color in the latch */ 881 /* foreground color */ 882 if (flip) 883 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 884 else 885 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 886 outw(GDCIDX, col | 0x00); /* set/reset */ 887 f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size 888 + scp->font_size - scp->cursor_base - 1]); 889 height = imin(scp->cursor_height, scp->font_size); 890 for (i = 0; i < height; ++i, --f) { 891 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 892 writeb(d, 0); 893 d -= line_width; 894 } 895 outw(GDCIDX, 0x0000); /* set/reset */ 896 outw(GDCIDX, 0x0001); /* set/reset enable */ 897 outw(GDCIDX, 0xff08); /* bit mask */ 898 } 899 900 static int pxlblinkrate = 0; 901 902 static void 903 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip) 904 { 905 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 906 return; 907 908 if (on) { 909 if (!blink) { 910 scp->status |= VR_CURSOR_ON; 911 draw_pxlcursor_direct(scp, at, on, flip); 912 } else if (++pxlblinkrate & 4) { 913 pxlblinkrate = 0; 914 scp->status ^= VR_CURSOR_ON; 915 draw_pxlcursor_direct(scp, at, 916 scp->status & VR_CURSOR_ON, 917 flip); 918 } 919 } else { 920 if (scp->status & VR_CURSOR_ON) 921 draw_pxlcursor_direct(scp, at, on, flip); 922 scp->status &= ~VR_CURSOR_ON; 923 } 924 if (blink) 925 scp->status |= VR_CURSOR_BLINK; 926 else 927 scp->status &= ~VR_CURSOR_BLINK; 928 } 929 930 static void 931 vga_pxlcursor_planar(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_planar(scp, at, on, flip); 940 } else if (++pxlblinkrate & 4) { 941 pxlblinkrate = 0; 942 scp->status ^= VR_CURSOR_ON; 943 draw_pxlcursor_planar(scp, at, 944 scp->status & VR_CURSOR_ON, 945 flip); 946 } 947 } else { 948 if (scp->status & VR_CURSOR_ON) 949 draw_pxlcursor_planar(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_pxlblink_direct(scr_stat *scp, int at, int flip) 960 { 961 if (!(scp->status & VR_CURSOR_BLINK)) 962 return; 963 if (!(++pxlblinkrate & 4)) 964 return; 965 pxlblinkrate = 0; 966 scp->status ^= VR_CURSOR_ON; 967 draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip); 968 } 969 970 static void 971 vga_pxlblink_planar(scr_stat *scp, int at, int flip) 972 { 973 if (!(scp->status & VR_CURSOR_BLINK)) 974 return; 975 if (!(++pxlblinkrate & 4)) 976 return; 977 pxlblinkrate = 0; 978 scp->status ^= VR_CURSOR_ON; 979 draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip); 980 } 981 982 #ifndef SC_NO_CUTPASTE 983 984 static void 985 draw_pxlmouse_direct(scr_stat *scp, int x, int y) 986 { 987 int line_width, pixel_size; 988 int xend, yend; 989 int i, j; 990 vm_offset_t draw_pos; 991 992 line_width = scp->sc->adp->va_line_width; 993 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 994 995 xend = imin(x + 8, 8 * (scp->xoff + scp->xsize)); 996 yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 997 998 draw_pos = scp->sc->adp->va_window + y * line_width + x * pixel_size; 999 1000 for (i = 0; i < (yend - y); i++) { 1001 for (j = (xend - x - 1); j >= 0; j--) { 1002 switch (scp->sc->adp->va_info.vi_depth) { 1003 case 32: 1004 if (mouse_or_mask[i] & 1 << (15 - j)) 1005 writel(draw_pos + 4 * j, 1006 scp->ega_palette[15]); 1007 else if (mouse_and_mask[i] & 1 << (15 - j)) 1008 writel(draw_pos + 4 * j, 1009 scp->ega_palette[0]); 1010 break; 1011 case 16: 1012 /* FALLTHROUGH */ 1013 case 15: 1014 if (mouse_or_mask[i] & 1 << (15 - j)) 1015 writew(draw_pos + 2 * j, 1016 scp->ega_palette[15]); 1017 else if (mouse_and_mask[i] & 1 << (15 - j)) 1018 writew(draw_pos + 2 * j, 1019 scp->ega_palette[0]); 1020 break; 1021 } 1022 } 1023 1024 draw_pos += line_width; 1025 } 1026 } 1027 1028 static void 1029 draw_pxlmouse_planar(scr_stat *scp, int x, int y) 1030 { 1031 vm_offset_t p; 1032 int line_width; 1033 int xoff, yoff; 1034 int ymax; 1035 u_short m; 1036 int i, j; 1037 1038 line_width = scp->sc->adp->va_line_width; 1039 xoff = (x - scp->xoff*8)%8; 1040 yoff = y - (y/line_width)*line_width; 1041 ymax = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 1042 1043 outw(GDCIDX, 0x0805); /* read mode 1, write mode 0 */ 1044 outw(GDCIDX, 0x0001); /* set/reset enable */ 1045 outw(GDCIDX, 0x0002); /* color compare */ 1046 outw(GDCIDX, 0x0007); /* color don't care */ 1047 outw(GDCIDX, 0xff08); /* bit mask */ 1048 outw(GDCIDX, 0x0803); /* data rotate/function select (and) */ 1049 p = scp->sc->adp->va_window + line_width*y + x/8; 1050 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1051 for (i = y, j = 0; i < ymax; ++i, ++j) { 1052 m = ~(mouse_and_mask[j] >> xoff); 1053 *(u_char *)p &= m >> 8; 1054 *(u_char *)(p + 1) &= m; 1055 p += line_width; 1056 } 1057 } else { 1058 xoff += 8; 1059 for (i = y, j = 0; i < ymax; ++i, ++j) { 1060 m = ~(mouse_and_mask[j] >> xoff); 1061 *(u_char *)p &= m; 1062 p += line_width; 1063 } 1064 } 1065 outw(GDCIDX, 0x1003); /* data rotate/function select (or) */ 1066 p = scp->sc->adp->va_window + line_width*y + x/8; 1067 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1068 for (i = y, j = 0; i < ymax; ++i, ++j) { 1069 m = mouse_or_mask[j] >> xoff; 1070 *(u_char *)p &= m >> 8; 1071 *(u_char *)(p + 1) &= m; 1072 p += line_width; 1073 } 1074 } else { 1075 for (i = y, j = 0; i < ymax; ++i, ++j) { 1076 m = mouse_or_mask[j] >> xoff; 1077 *(u_char *)p &= m; 1078 p += line_width; 1079 } 1080 } 1081 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 1082 outw(GDCIDX, 0x0003); /* data rotate/function select */ 1083 } 1084 1085 static void 1086 remove_pxlmouse(scr_stat *scp, int x, int y) 1087 { 1088 int col, row; 1089 int pos; 1090 int i; 1091 1092 /* erase the mouse cursor image */ 1093 col = x/8 - scp->xoff; 1094 row = y/scp->font_size - scp->yoff; 1095 pos = row*scp->xsize + col; 1096 i = (col < scp->xsize - 1) ? 2 : 1; 1097 (*scp->rndr->draw)(scp, pos, i, FALSE); 1098 if (row < scp->ysize - 1) 1099 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 1100 } 1101 1102 static void 1103 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on) 1104 { 1105 if (on) 1106 draw_pxlmouse_direct(scp, x, y); 1107 else 1108 remove_pxlmouse(scp, x, y); 1109 } 1110 1111 static void 1112 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on) 1113 { 1114 if (on) 1115 draw_pxlmouse_planar(scp, x, y); 1116 else 1117 remove_pxlmouse(scp, x, y); 1118 } 1119 1120 #endif /* SC_NO_CUTPASTE */ 1121 #endif /* SC_PIXEL_MODE */ 1122 1123 #ifndef SC_NO_MODE_CHANGE 1124 1125 /* graphics mode renderer */ 1126 1127 static void 1128 vga_grborder(scr_stat *scp, int color) 1129 { 1130 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 1131 } 1132 1133 #endif 1134