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.12 2005/04/26 21:23:50 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_draw_border_t vga_txtborder; 53 static vr_draw_t vga_txtdraw; 54 static vr_set_cursor_t vga_txtcursor_shape; 55 static vr_draw_cursor_t vga_txtcursor; 56 static vr_blink_cursor_t vga_txtblink; 57 #ifndef SC_NO_CUTPASTE 58 static vr_draw_mouse_t vga_txtmouse; 59 #else 60 #define vga_txtmouse (vr_draw_mouse_t *)vga_nop 61 #endif 62 63 #ifdef SC_PIXEL_MODE 64 static vr_init_t vga_rndrinit; 65 static vr_draw_border_t vga_pxlborder_direct; 66 static vr_draw_border_t vga_pxlborder_planar; 67 static vr_draw_t vga_egadraw; 68 static vr_draw_t vga_vgadraw_direct; 69 static vr_draw_t vga_vgadraw_planar; 70 static vr_set_cursor_t vga_pxlcursor_shape; 71 static vr_draw_cursor_t vga_pxlcursor_direct; 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_planar; 75 #ifndef SC_NO_CUTPASTE 76 static vr_draw_mouse_t vga_pxlmouse_direct; 77 static vr_draw_mouse_t vga_pxlmouse_planar; 78 #else 79 #define vga_pxlmouse_direct (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 (vr_init_t *)vga_nop, 92 vga_txtborder, 93 vga_txtdraw, 94 vga_txtcursor_shape, 95 vga_txtcursor, 96 vga_txtblink, 97 (vr_set_mouse_t *)vga_nop, 98 vga_txtmouse, 99 }; 100 RENDERER(mda, 0, txtrndrsw, vga_set); 101 RENDERER(cga, 0, txtrndrsw, vga_set); 102 RENDERER(ega, 0, txtrndrsw, vga_set); 103 RENDERER(vga, 0, txtrndrsw, vga_set); 104 105 #ifdef SC_PIXEL_MODE 106 static sc_rndr_sw_t egarndrsw = { 107 (vr_init_t *)vga_nop, 108 vga_pxlborder_planar, 109 vga_egadraw, 110 vga_pxlcursor_shape, 111 vga_pxlcursor_planar, 112 vga_pxlblink_planar, 113 (vr_set_mouse_t *)vga_nop, 114 vga_pxlmouse_planar, 115 }; 116 RENDERER(ega, PIXEL_MODE, egarndrsw, vga_set); 117 118 static sc_rndr_sw_t vgarndrsw = { 119 vga_rndrinit, 120 (vr_draw_border_t *)vga_nop, 121 (vr_draw_t *)vga_nop, 122 vga_pxlcursor_shape, 123 (vr_draw_cursor_t *)vga_nop, 124 (vr_blink_cursor_t *)vga_nop, 125 (vr_set_mouse_t *)vga_nop, 126 (vr_draw_mouse_t *)vga_nop, 127 }; 128 RENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set); 129 #endif /* SC_PIXEL_MODE */ 130 131 #ifndef SC_NO_MODE_CHANGE 132 static sc_rndr_sw_t grrndrsw = { 133 (vr_init_t *)vga_nop, 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_set_mouse_t *)vga_nop, 140 (vr_draw_mouse_t *)vga_nop, 141 }; 142 RENDERER(cga, GRAPHICS_MODE, grrndrsw, vga_set); 143 RENDERER(ega, GRAPHICS_MODE, grrndrsw, vga_set); 144 RENDERER(vga, GRAPHICS_MODE, 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 vm_offset_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 = sc_vtb_pointer(&scp->scr, from); count-- > 0; ++from) { 185 c = sc_vtb_getc(&scp->vtb, from); 186 a = sc_vtb_geta(&scp->vtb, from); 187 a = (a & 0x8800) | ((a & 0x7000) >> 4) 188 | ((a & 0x0700) << 4); 189 p = sc_vtb_putchar(&scp->scr, p, c, a); 190 } 191 } else { 192 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count); 193 } 194 } 195 196 static void 197 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink) 198 { 199 if (base < 0 || base >= scp->font_size) 200 return; 201 /* the caller may set height <= 0 in order to disable the cursor */ 202 #if 0 203 scp->cursor_base = base; 204 scp->cursor_height = height; 205 #endif 206 (*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp, 207 base, height, 208 scp->font_size, blink); 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_size < 14) { 227 font = sc->font_8; 228 h = 8; 229 } else if (scp->font_size >= 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 #ifndef SC_NO_CUTPASTE 324 325 static void 326 draw_txtmouse(scr_stat *scp, int x, int y) 327 { 328 #ifndef SC_ALT_MOUSE_IMAGE 329 if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) { 330 u_char font_buf[128]; 331 u_short cursor[32]; 332 u_char c; 333 int pos; 334 int xoffset, yoffset; 335 int crtc_addr; 336 int i; 337 338 /* prepare mousepointer char's bitmaps */ 339 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 340 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size, 341 &font_buf[0], scp->font_size); 342 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size, 343 &font_buf[32], scp->font_size); 344 bcopy(scp->font 345 + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size, 346 &font_buf[64], scp->font_size); 347 bcopy(scp->font 348 + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size, 349 &font_buf[96], scp->font_size); 350 for (i = 0; i < scp->font_size; ++i) { 351 cursor[i] = font_buf[i]<<8 | font_buf[i+32]; 352 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96]; 353 } 354 355 /* now and-or in the mousepointer image */ 356 xoffset = x%8; 357 yoffset = y%scp->font_size; 358 for (i = 0; i < 16; ++i) { 359 cursor[i + yoffset] = 360 (cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset)) 361 | (mouse_or_mask[i] >> xoffset); 362 } 363 for (i = 0; i < scp->font_size; ++i) { 364 font_buf[i] = (cursor[i] & 0xff00) >> 8; 365 font_buf[i + 32] = cursor[i] & 0xff; 366 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8; 367 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff; 368 } 369 370 #if 1 371 /* wait for vertical retrace to avoid jitter on some videocards */ 372 crtc_addr = scp->sc->adp->va_crtc_addr; 373 while (!(inb(crtc_addr + 6) & 0x08)) /* idle */ ; 374 #endif 375 c = scp->sc->mouse_char; 376 (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf, 377 c, 4); 378 379 sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos)); 380 /* FIXME: may be out of range! */ 381 sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2, 382 sc_vtb_geta(&scp->scr, pos + scp->xsize)); 383 if (x < (scp->xsize - 1)*8) { 384 sc_vtb_putc(&scp->scr, pos + 1, c + 1, 385 sc_vtb_geta(&scp->scr, pos + 1)); 386 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3, 387 sc_vtb_geta(&scp->scr, pos + scp->xsize + 1)); 388 } 389 } else 390 #endif /* SC_ALT_MOUSE_IMAGE */ 391 { 392 /* Red, magenta and brown are mapped to green to to keep it readable */ 393 static const int col_conv[16] = { 394 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14 395 }; 396 int pos; 397 int color; 398 int a; 399 400 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 401 a = sc_vtb_geta(&scp->scr, pos); 402 if (scp->sc->adp->va_flags & V_ADP_COLOR) 403 color = (col_conv[(a & 0xf000) >> 12] << 12) 404 | ((a & 0x0f00) | 0x0800); 405 else 406 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4); 407 sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color); 408 } 409 } 410 411 static void 412 remove_txtmouse(scr_stat *scp, int x, int y) 413 { 414 } 415 416 static void 417 vga_txtmouse(scr_stat *scp, int x, int y, int on) 418 { 419 if (on) 420 draw_txtmouse(scp, x, y); 421 else 422 remove_txtmouse(scp, x, y); 423 } 424 425 #endif /* SC_NO_CUTPASTE */ 426 427 #ifdef SC_PIXEL_MODE 428 429 /* pixel (raster text) mode renderer */ 430 431 static void 432 vga_rndrinit(scr_stat *scp) 433 { 434 if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PLANAR) { 435 scp->rndr->draw_border = vga_pxlborder_planar; 436 scp->rndr->draw = vga_vgadraw_planar; 437 scp->rndr->draw_cursor = vga_pxlcursor_planar; 438 scp->rndr->blink_cursor = vga_pxlblink_planar; 439 scp->rndr->draw_mouse = vga_pxlmouse_planar; 440 } else if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_DIRECT) { 441 scp->rndr->draw_border = vga_pxlborder_direct; 442 scp->rndr->draw = vga_vgadraw_direct; 443 scp->rndr->draw_cursor = vga_pxlcursor_direct; 444 scp->rndr->blink_cursor = vga_pxlblink_direct; 445 scp->rndr->draw_mouse = vga_pxlmouse_direct; 446 } 447 } 448 449 static void 450 vga_pxlborder_direct(scr_stat *scp, int color) 451 { 452 int i, x, y; 453 int line_width, pixel_size; 454 uint32_t u32 = 0; 455 vm_offset_t draw_pos, draw_end, p; 456 457 line_width = scp->sc->adp->va_line_width; 458 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 459 460 for (i = 0; i < 4 / pixel_size; ++i) 461 u32 += scp->ega_palette[color] << (i * 8 * pixel_size); 462 463 if (scp->yoff > 0) { 464 draw_pos = scp->sc->adp->va_window; 465 draw_end = draw_pos + 466 line_width * scp->yoff * scp->font_size; 467 468 for (p = draw_pos; p < draw_end; p += 4) 469 writel(p, u32); 470 } 471 472 y = (scp->yoff + scp->ysize) * scp->font_size; 473 474 if (scp->ypixel > y) { 475 draw_pos = scp->sc->adp->va_window + line_width * y; 476 draw_end = draw_pos + line_width * (scp->ypixel - y); 477 478 for (p = draw_pos; p < draw_end; p += 4) 479 writel(p, u32); 480 } 481 482 y = scp->yoff * scp->font_size; 483 x = scp->xpixel / 8 - scp->xoff - scp->xsize; 484 485 for (i = 0; i < scp->ysize * scp->font_size; ++i) { 486 if (scp->xoff > 0) { 487 draw_pos = scp->sc->adp->va_window + 488 line_width * (y + i); 489 draw_end = draw_pos + scp->xoff * 8 * pixel_size; 490 491 for (p = draw_pos; p < draw_end; p += 4) 492 writel(p, u32); 493 } 494 495 if (x > 0) { 496 draw_pos = scp->sc->adp->va_window + 497 line_width * (y + i) + 498 scp->xoff * 8 * pixel_size + 499 scp->xsize * 8 * pixel_size; 500 draw_end = draw_pos + x * 8 * pixel_size; 501 502 for (p = draw_pos; p < draw_end; p += 4) 503 writel(p, u32); 504 } 505 } 506 } 507 508 static void 509 vga_pxlborder_planar(scr_stat *scp, int color) 510 { 511 vm_offset_t p; 512 int line_width; 513 int x; 514 int y; 515 int i; 516 517 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 518 519 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 520 outw(GDCIDX, 0x0003); /* data rotate/function select */ 521 outw(GDCIDX, 0x0f01); /* set/reset enable */ 522 outw(GDCIDX, 0xff08); /* bit mask */ 523 outw(GDCIDX, (color << 8) | 0x00); /* set/reset */ 524 line_width = scp->sc->adp->va_line_width; 525 p = scp->sc->adp->va_window; 526 if (scp->yoff > 0) 527 bzero_io((void *)p, line_width*scp->yoff*scp->font_size); 528 y = (scp->yoff + scp->ysize)*scp->font_size; 529 if (scp->ypixel > y) 530 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y)); 531 y = scp->yoff*scp->font_size; 532 x = scp->xpixel/8 - scp->xoff - scp->xsize; 533 for (i = 0; i < scp->ysize*scp->font_size; ++i) { 534 if (scp->xoff > 0) 535 bzero_io((void *)(p + line_width*(y + i)), scp->xoff); 536 if (x > 0) 537 bzero_io((void *)(p + line_width*(y + i) 538 + scp->xoff + scp->xsize), x); 539 } 540 outw(GDCIDX, 0x0000); /* set/reset */ 541 outw(GDCIDX, 0x0001); /* set/reset enable */ 542 } 543 544 static void 545 vga_egadraw(scr_stat *scp, int from, int count, int flip) 546 { 547 vm_offset_t d; 548 vm_offset_t e; 549 u_char *f; 550 u_short bg; 551 u_short col1, col2; 552 int line_width; 553 int i, j; 554 int a; 555 u_char c; 556 557 line_width = scp->sc->adp->va_line_width; 558 559 d = VIDEO_MEMORY_POS(scp, from, 1); 560 561 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 562 outw(GDCIDX, 0x0003); /* data rotate/function select */ 563 outw(GDCIDX, 0x0f01); /* set/reset enable */ 564 bg = -1; 565 if (from + count > scp->xsize*scp->ysize) 566 count = scp->xsize*scp->ysize - from; 567 for (i = from; count-- > 0; ++i) { 568 a = sc_vtb_geta(&scp->vtb, i); 569 if (flip) { 570 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 571 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 572 } else { 573 col1 = (a & 0x0f00); 574 col2 = (a & 0xf000) >> 4; 575 } 576 /* set background color in EGA/VGA latch */ 577 if (bg != col2) { 578 bg = col2; 579 outw(GDCIDX, bg | 0x00); /* set/reset */ 580 outw(GDCIDX, 0xff08); /* bit mask */ 581 writeb(d, 0); 582 c = readb(d); /* set bg color in the latch */ 583 } 584 /* foreground color */ 585 outw(GDCIDX, col1 | 0x00); /* set/reset */ 586 e = d; 587 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]); 588 for (j = 0; j < scp->font_size; ++j, ++f) { 589 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 590 writeb(e, 0); 591 e += line_width; 592 } 593 ++d; 594 if ((i % scp->xsize) == scp->xsize - 1) 595 d += scp->xoff*2 596 + (scp->font_size - 1)*line_width; 597 } 598 outw(GDCIDX, 0x0000); /* set/reset */ 599 outw(GDCIDX, 0x0001); /* set/reset enable */ 600 outw(GDCIDX, 0xff08); /* bit mask */ 601 } 602 603 static void 604 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip) 605 { 606 int line_width, pixel_size; 607 int a, i, j, k, l, pos; 608 uint32_t fg, bg, u32; 609 unsigned char *char_data; 610 vm_offset_t draw_pos, p; 611 612 line_width = scp->sc->adp->va_line_width; 613 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 614 615 draw_pos = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size); 616 617 if (from + count > scp->xsize * scp->ysize) 618 count = scp->xsize * scp->ysize - from; 619 620 for (i = from; count-- > 0; ++i) { 621 a = sc_vtb_geta(&scp->vtb, i); 622 623 if (flip) { 624 fg = scp->ega_palette[(((a & 0x7000) >> 4) | 625 (a & 0x0800)) >> 8]; 626 bg = scp->ega_palette[(((a & 0x8000) >> 4) | 627 (a & 0x0700)) >> 8]; 628 } else { 629 fg = scp->ega_palette[(a & 0x0f00) >> 8]; 630 bg = scp->ega_palette[(a & 0xf000) >> 12]; 631 } 632 633 p = draw_pos; 634 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 635 scp->font_size]); 636 637 for (j = 0; j < scp->font_size; ++j, ++char_data) { 638 pos = 7; 639 640 for (k = 0; k < 2 * pixel_size; ++k) { 641 u32 = 0; 642 643 for (l = 0; l < 4 / pixel_size; ++l) { 644 u32 += (*char_data & (1 << pos--) ? 645 fg : bg) << (l * 8 * pixel_size); 646 } 647 648 writel(p, u32); 649 p += 4; 650 } 651 652 p += line_width - 8 * pixel_size; 653 } 654 655 draw_pos += 8 * pixel_size; 656 657 if ((i % scp->xsize) == scp->xsize - 1) 658 draw_pos += scp->xoff * 16 * pixel_size + 659 (scp->font_size - 1) * line_width; 660 } 661 } 662 663 static void 664 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip) 665 { 666 vm_offset_t d; 667 vm_offset_t e; 668 u_char *f; 669 u_short bg; 670 u_short col1, col2; 671 int line_width; 672 int i, j; 673 int a; 674 u_char c; 675 676 d = VIDEO_MEMORY_POS(scp, from, 1); 677 678 line_width = scp->sc->adp->va_line_width; 679 680 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 681 outw(GDCIDX, 0x0003); /* data rotate/function select */ 682 outw(GDCIDX, 0x0f01); /* set/reset enable */ 683 outw(GDCIDX, 0xff08); /* bit mask */ 684 bg = -1; 685 if (from + count > scp->xsize*scp->ysize) 686 count = scp->xsize*scp->ysize - from; 687 for (i = from; count-- > 0; ++i) { 688 a = sc_vtb_geta(&scp->vtb, i); 689 if (flip) { 690 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 691 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 692 } else { 693 col1 = (a & 0x0f00); 694 col2 = (a & 0xf000) >> 4; 695 } 696 /* set background color in EGA/VGA latch */ 697 if (bg != col2) { 698 bg = col2; 699 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 700 outw(GDCIDX, bg | 0x00); /* set/reset */ 701 writeb(d, 0); 702 c = readb(d); /* set bg color in the latch */ 703 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 704 } 705 /* foreground color */ 706 outw(GDCIDX, col1 | 0x00); /* set/reset */ 707 e = d; 708 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]); 709 for (j = 0; j < scp->font_size; ++j, ++f) { 710 writeb(e, *f); 711 e += line_width; 712 } 713 ++d; 714 if ((i % scp->xsize) == scp->xsize - 1) 715 d += scp->xoff*2 716 + (scp->font_size - 1)*line_width; 717 } 718 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 719 outw(GDCIDX, 0x0000); /* set/reset */ 720 outw(GDCIDX, 0x0001); /* set/reset enable */ 721 } 722 723 static void 724 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink) 725 { 726 if (base < 0 || base >= scp->font_size) 727 return; 728 /* the caller may set height <= 0 in order to disable the cursor */ 729 #if 0 730 scp->cursor_base = base; 731 scp->cursor_height = height; 732 #endif 733 } 734 735 static void 736 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip) 737 { 738 int line_width, pixel_size, height; 739 int a, i, j, k, pos; 740 uint32_t fg, bg, u32; 741 unsigned char *char_data; 742 vm_offset_t draw_pos; 743 744 line_width = scp->sc->adp->va_line_width; 745 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 746 747 draw_pos = VIDEO_MEMORY_POS(scp, at, 8 * pixel_size) + 748 (scp->font_size - scp->cursor_base - 1) * line_width; 749 750 a = sc_vtb_geta(&scp->vtb, at); 751 752 if (flip) { 753 fg = scp->ega_palette[((on) ? (a & 0x0f00) : 754 ((a & 0xf000) >> 4)) >> 8]; 755 bg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 756 (a & 0x0f00)) >> 8]; 757 } else { 758 fg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 759 (a & 0x0f00)) >> 8]; 760 bg = scp->ega_palette[((on) ? (a & 0x0f00) : 761 ((a & 0xf000) >> 4)) >> 8]; 762 } 763 764 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size + 765 scp->font_size - scp->cursor_base - 1]); 766 767 height = imin(scp->cursor_height, scp->font_size); 768 769 for (i = 0; i < height; ++i, --char_data) { 770 pos = 7; 771 772 for (j = 0; j < 2 * pixel_size; ++j) { 773 u32 = 0; 774 775 for (k = 0; k < 4 / pixel_size; ++k) { 776 u32 += (*char_data & (1 << pos--) ? 777 fg : bg) << (k * 8 * pixel_size); 778 } 779 780 writel(draw_pos, u32); 781 draw_pos += 4; 782 } 783 784 draw_pos -= line_width + 8 * pixel_size; 785 } 786 } 787 788 static void 789 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip) 790 { 791 vm_offset_t d; 792 u_char *f; 793 int line_width; 794 int height; 795 int col; 796 int a; 797 int i; 798 u_char c; 799 800 line_width = scp->sc->adp->va_line_width; 801 802 d = VIDEO_MEMORY_POS(scp, at, 1) + 803 (scp->font_size - scp->cursor_base - 1) * line_width; 804 805 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 806 outw(GDCIDX, 0x0003); /* data rotate/function select */ 807 outw(GDCIDX, 0x0f01); /* set/reset enable */ 808 /* set background color in EGA/VGA latch */ 809 a = sc_vtb_geta(&scp->vtb, at); 810 if (flip) 811 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 812 else 813 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 814 outw(GDCIDX, col | 0x00); /* set/reset */ 815 outw(GDCIDX, 0xff08); /* bit mask */ 816 writeb(d, 0); 817 c = readb(d); /* set bg color in the latch */ 818 /* foreground color */ 819 if (flip) 820 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 821 else 822 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 823 outw(GDCIDX, col | 0x00); /* set/reset */ 824 f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size 825 + scp->font_size - scp->cursor_base - 1]); 826 height = imin(scp->cursor_height, scp->font_size); 827 for (i = 0; i < height; ++i, --f) { 828 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 829 writeb(d, 0); 830 d -= line_width; 831 } 832 outw(GDCIDX, 0x0000); /* set/reset */ 833 outw(GDCIDX, 0x0001); /* set/reset enable */ 834 outw(GDCIDX, 0xff08); /* bit mask */ 835 } 836 837 static int pxlblinkrate = 0; 838 839 static void 840 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip) 841 { 842 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 843 return; 844 845 if (on) { 846 if (!blink) { 847 scp->status |= VR_CURSOR_ON; 848 draw_pxlcursor_direct(scp, at, on, flip); 849 } else if (++pxlblinkrate & 4) { 850 pxlblinkrate = 0; 851 scp->status ^= VR_CURSOR_ON; 852 draw_pxlcursor_direct(scp, at, 853 scp->status & VR_CURSOR_ON, 854 flip); 855 } 856 } else { 857 if (scp->status & VR_CURSOR_ON) 858 draw_pxlcursor_direct(scp, at, on, flip); 859 scp->status &= ~VR_CURSOR_ON; 860 } 861 if (blink) 862 scp->status |= VR_CURSOR_BLINK; 863 else 864 scp->status &= ~VR_CURSOR_BLINK; 865 } 866 867 static void 868 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip) 869 { 870 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 871 return; 872 873 if (on) { 874 if (!blink) { 875 scp->status |= VR_CURSOR_ON; 876 draw_pxlcursor_planar(scp, at, on, flip); 877 } else if (++pxlblinkrate & 4) { 878 pxlblinkrate = 0; 879 scp->status ^= VR_CURSOR_ON; 880 draw_pxlcursor_planar(scp, at, 881 scp->status & VR_CURSOR_ON, 882 flip); 883 } 884 } else { 885 if (scp->status & VR_CURSOR_ON) 886 draw_pxlcursor_planar(scp, at, on, flip); 887 scp->status &= ~VR_CURSOR_ON; 888 } 889 if (blink) 890 scp->status |= VR_CURSOR_BLINK; 891 else 892 scp->status &= ~VR_CURSOR_BLINK; 893 } 894 895 static void 896 vga_pxlblink_direct(scr_stat *scp, int at, int flip) 897 { 898 if (!(scp->status & VR_CURSOR_BLINK)) 899 return; 900 if (!(++pxlblinkrate & 4)) 901 return; 902 pxlblinkrate = 0; 903 scp->status ^= VR_CURSOR_ON; 904 draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip); 905 } 906 907 static void 908 vga_pxlblink_planar(scr_stat *scp, int at, int flip) 909 { 910 if (!(scp->status & VR_CURSOR_BLINK)) 911 return; 912 if (!(++pxlblinkrate & 4)) 913 return; 914 pxlblinkrate = 0; 915 scp->status ^= VR_CURSOR_ON; 916 draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip); 917 } 918 919 #ifndef SC_NO_CUTPASTE 920 921 static void 922 draw_pxlmouse_direct(scr_stat *scp, int x, int y) 923 { 924 int line_width, pixel_size; 925 int xend, yend; 926 int i, j; 927 vm_offset_t draw_pos; 928 929 line_width = scp->sc->adp->va_line_width; 930 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 931 932 xend = imin(x + 8, 8 * (scp->xoff + scp->xsize)); 933 yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 934 935 draw_pos = scp->sc->adp->va_window + y * line_width + x * pixel_size; 936 937 for (i = 0; i < (yend - y); i++) { 938 for (j = (xend - x - 1); j >= 0; j--) { 939 switch (scp->sc->adp->va_info.vi_depth) { 940 case 32: 941 if (mouse_or_mask[i] & 1 << (15 - j)) 942 writel(draw_pos + 4 * j, 943 scp->ega_palette[15]); 944 else if (mouse_and_mask[i] & 1 << (15 - j)) 945 writel(draw_pos + 4 * j, 946 scp->ega_palette[0]); 947 break; 948 case 16: 949 /* FALLTHROUGH */ 950 case 15: 951 if (mouse_or_mask[i] & 1 << (15 - j)) 952 writew(draw_pos + 2 * j, 953 scp->ega_palette[15]); 954 else if (mouse_and_mask[i] & 1 << (15 - j)) 955 writew(draw_pos + 2 * j, 956 scp->ega_palette[0]); 957 break; 958 } 959 } 960 961 draw_pos += line_width; 962 } 963 } 964 965 static void 966 draw_pxlmouse_planar(scr_stat *scp, int x, int y) 967 { 968 vm_offset_t p; 969 int line_width; 970 int xoff, yoff; 971 int ymax; 972 u_short m; 973 int i, j; 974 975 line_width = scp->sc->adp->va_line_width; 976 xoff = (x - scp->xoff*8)%8; 977 yoff = y - (y/line_width)*line_width; 978 ymax = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 979 980 outw(GDCIDX, 0x0805); /* read mode 1, write mode 0 */ 981 outw(GDCIDX, 0x0001); /* set/reset enable */ 982 outw(GDCIDX, 0x0002); /* color compare */ 983 outw(GDCIDX, 0x0007); /* color don't care */ 984 outw(GDCIDX, 0xff08); /* bit mask */ 985 outw(GDCIDX, 0x0803); /* data rotate/function select (and) */ 986 p = scp->sc->adp->va_window + line_width*y + x/8; 987 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 988 for (i = y, j = 0; i < ymax; ++i, ++j) { 989 m = ~(mouse_and_mask[j] >> xoff); 990 *(u_char *)p &= m >> 8; 991 *(u_char *)(p + 1) &= m; 992 p += line_width; 993 } 994 } else { 995 xoff += 8; 996 for (i = y, j = 0; i < ymax; ++i, ++j) { 997 m = ~(mouse_and_mask[j] >> xoff); 998 *(u_char *)p &= m; 999 p += line_width; 1000 } 1001 } 1002 outw(GDCIDX, 0x1003); /* data rotate/function select (or) */ 1003 p = scp->sc->adp->va_window + line_width*y + x/8; 1004 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1005 for (i = y, j = 0; i < ymax; ++i, ++j) { 1006 m = mouse_or_mask[j] >> xoff; 1007 *(u_char *)p &= m >> 8; 1008 *(u_char *)(p + 1) &= m; 1009 p += line_width; 1010 } 1011 } else { 1012 for (i = y, j = 0; i < ymax; ++i, ++j) { 1013 m = mouse_or_mask[j] >> xoff; 1014 *(u_char *)p &= m; 1015 p += line_width; 1016 } 1017 } 1018 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 1019 outw(GDCIDX, 0x0003); /* data rotate/function select */ 1020 } 1021 1022 static void 1023 remove_pxlmouse(scr_stat *scp, int x, int y) 1024 { 1025 int col, row; 1026 int pos; 1027 int i; 1028 1029 /* erase the mouse cursor image */ 1030 col = x/8 - scp->xoff; 1031 row = y/scp->font_size - scp->yoff; 1032 pos = row*scp->xsize + col; 1033 i = (col < scp->xsize - 1) ? 2 : 1; 1034 (*scp->rndr->draw)(scp, pos, i, FALSE); 1035 if (row < scp->ysize - 1) 1036 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 1037 } 1038 1039 static void 1040 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on) 1041 { 1042 if (on) 1043 draw_pxlmouse_direct(scp, x, y); 1044 else 1045 remove_pxlmouse(scp, x, y); 1046 } 1047 1048 static void 1049 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on) 1050 { 1051 if (on) 1052 draw_pxlmouse_planar(scp, x, y); 1053 else 1054 remove_pxlmouse(scp, x, y); 1055 } 1056 1057 #endif /* SC_NO_CUTPASTE */ 1058 #endif /* SC_PIXEL_MODE */ 1059 1060 #ifndef SC_NO_MODE_CHANGE 1061 1062 /* graphics mode renderer */ 1063 1064 static void 1065 vga_grborder(scr_stat *scp, int color) 1066 { 1067 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 1068 } 1069 1070 #endif 1071