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