1 /* $NetBSD: hpcfb.c,v 1.41 2007/03/04 06:01:46 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 5 * Shin Takemura and PocketBSD Project. All rights reserved. 6 * Copyright (c) 2000,2001 7 * SATO Kazumi. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 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 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the PocketBSD project 20 * and its contributors. 21 * 4. Neither the name of the project nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 */ 38 39 /* 40 * jump scroll, scroll thread, multiscreen, virtual text vram 41 * and hpcfb_emulops functions 42 * written by SATO Kazumi. 43 */ 44 45 #include <sys/cdefs.h> 46 __KERNEL_RCSID(0, "$NetBSD: hpcfb.c,v 1.41 2007/03/04 06:01:46 christos Exp $"); 47 48 #ifdef _KERNEL_OPT 49 #include "opt_hpcfb.h" 50 #endif 51 52 #include <sys/param.h> 53 #include <sys/systm.h> 54 #include <sys/kernel.h> 55 #include <sys/signalvar.h> 56 #include <sys/proc.h> 57 #include <sys/kthread.h> 58 #include <sys/lock.h> 59 #include <sys/user.h> 60 #include <sys/device.h> 61 #include <sys/conf.h> 62 #include <sys/malloc.h> 63 #include <sys/buf.h> 64 #include <sys/ioctl.h> 65 66 #include <uvm/uvm_extern.h> 67 68 #include <machine/bus.h> 69 70 #include <dev/wscons/wsconsio.h> 71 #include <dev/wscons/wsdisplayvar.h> 72 #include <dev/wscons/wscons_callbacks.h> 73 74 #include <dev/wsfont/wsfont.h> 75 #include <dev/rasops/rasops.h> 76 77 #include <dev/hpc/hpcfbvar.h> 78 #include <dev/hpc/hpcfbio.h> 79 80 #include "bivideo.h" 81 #if NBIVIDEO > 0 82 #include <dev/hpc/bivideovar.h> 83 #endif 84 85 #ifdef FBDEBUG 86 int hpcfb_debug = 0; 87 #define DPRINTF(arg) if (hpcfb_debug) printf arg 88 #else 89 #define DPRINTF(arg) do {} while (/* CONSTCOND */ 0) 90 #endif 91 92 #ifndef HPCFB_MAX_COLUMN 93 #define HPCFB_MAX_COLUMN 130 94 #endif /* HPCFB_MAX_COLUMN */ 95 #ifndef HPCFB_MAX_ROW 96 #define HPCFB_MAX_ROW 80 97 #endif /* HPCFB_MAX_ROW */ 98 99 /* 100 * currently experimental 101 #define HPCFB_JUMP 102 */ 103 104 struct hpcfb_vchar { 105 u_int c; 106 long attr; 107 }; 108 109 struct hpcfb_tvrow { 110 int maxcol; 111 int spacecol; 112 struct hpcfb_vchar col[HPCFB_MAX_COLUMN]; 113 }; 114 115 struct hpcfb_devconfig { 116 struct rasops_info dc_rinfo; /* rasops information */ 117 118 int dc_blanked; /* currently had video disabled */ 119 struct hpcfb_softc *dc_sc; 120 int dc_rows; 121 int dc_cols; 122 struct hpcfb_tvrow *dc_tvram; 123 int dc_curx; 124 int dc_cury; 125 #ifdef HPCFB_JUMP 126 int dc_min_row; 127 int dc_max_row; 128 int dc_scroll; 129 struct callout dc_scroll_ch; 130 int dc_scroll_src; 131 int dc_scroll_dst; 132 int dc_scroll_num; 133 #endif /* HPCFB_JUMP */ 134 volatile int dc_state; 135 #define HPCFB_DC_CURRENT 0x80000000 136 #define HPCFB_DC_DRAWING 0x01 /* drawing raster ops */ 137 #define HPCFB_DC_TDRAWING 0x02 /* drawing tvram */ 138 #define HPCFB_DC_SCROLLPENDING 0x04 /* scroll is pending */ 139 #define HPCFB_DC_UPDATE 0x08 /* tvram update */ 140 #define HPCFB_DC_SCRDELAY 0x10 /* scroll time but delay it */ 141 #define HPCFB_DC_SCRTHREAD 0x20 /* in scroll thread or callout */ 142 #define HPCFB_DC_UPDATEALL 0x40 /* need to redraw all */ 143 #define HPCFB_DC_ABORT 0x80 /* abort redrawing */ 144 #define HPCFB_DC_SWITCHREQ 0x100 /* switch request exist */ 145 int dc_memsize; 146 u_char *dc_fbaddr; 147 }; 148 149 #define IS_DRAWABLE(dc) \ 150 (((dc)->dc_state&HPCFB_DC_CURRENT)&& \ 151 (((dc)->dc_state&(HPCFB_DC_DRAWING|HPCFB_DC_SWITCHREQ)) == 0)) 152 153 #define HPCFB_MAX_SCREEN 5 154 #define HPCFB_MAX_JUMP 5 155 156 struct hpcfb_softc { 157 struct device sc_dev; 158 struct hpcfb_devconfig *sc_dc; /* device configuration */ 159 const struct hpcfb_accessops *sc_accessops; 160 void *sc_accessctx; 161 void *sc_powerhook; /* power management hook */ 162 struct device *sc_wsdisplay; 163 int sc_screen_resumed; 164 int sc_polling; 165 int sc_mapping; 166 struct proc *sc_thread; 167 struct lock sc_lock; 168 void *sc_wantedscreen; 169 void (*sc_switchcb)(void *, int, int); 170 void *sc_switchcbarg; 171 struct callout sc_switch_callout; 172 int sc_nfbconf; 173 struct hpcfb_fbconf *sc_fbconflist; 174 }; 175 176 /* 177 * function prototypes 178 */ 179 int hpcfbmatch(struct device *, struct cfdata *, void *); 180 void hpcfbattach(struct device *, struct device *, void *); 181 int hpcfbprint(void *, const char *); 182 183 int hpcfb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 184 paddr_t hpcfb_mmap(void *, void *, off_t, int); 185 186 void hpcfb_refresh_screen(struct hpcfb_softc *); 187 void hpcfb_doswitch(struct hpcfb_softc *); 188 189 #ifdef HPCFB_JUMP 190 static void hpcfb_create_thread(void *); 191 static void hpcfb_thread(void *); 192 #endif /* HPCFB_JUMP */ 193 194 static int hpcfb_init(struct hpcfb_fbconf *, struct hpcfb_devconfig *); 195 static int hpcfb_alloc_screen(void *, const struct wsscreen_descr *, 196 void **, int *, int *, long *); 197 static void hpcfb_free_screen(void *, void *); 198 static int hpcfb_show_screen(void *, void *, int, 199 void (*) (void *, int, int), void *); 200 static void hpcfb_pollc(void *, int); 201 static void hpcfb_power(int, void *); 202 static void hpcfb_cmap_reorder(struct hpcfb_fbconf *, 203 struct hpcfb_devconfig *); 204 205 void hpcfb_cursor(void *, int, int, int); 206 int hpcfb_mapchar(void *, int, unsigned int *); 207 void hpcfb_putchar(void *, int, int, u_int, long); 208 void hpcfb_copycols(void *, int, int, int, int); 209 void hpcfb_erasecols(void *, int, int, int, long); 210 void hpcfb_redraw(void *, int, int, int); 211 void hpcfb_copyrows(void *, int, int, int); 212 void hpcfb_eraserows(void *, int, int, long); 213 int hpcfb_allocattr(void *, int, int, int, long *); 214 void hpcfb_cursor_raw(void *, int, int, int); 215 216 #ifdef HPCFB_JUMP 217 void hpcfb_update(void *); 218 void hpcfb_do_scroll(void *); 219 void hpcfb_check_update(void *); 220 #endif /* HPCFB_JUMP */ 221 222 struct wsdisplay_emulops hpcfb_emulops = { 223 .cursor = hpcfb_cursor, 224 .mapchar = hpcfb_mapchar, 225 .putchar = hpcfb_putchar, 226 .copycols = hpcfb_copycols, 227 .erasecols = hpcfb_erasecols, 228 .copyrows = hpcfb_copyrows, 229 .eraserows = hpcfb_eraserows, 230 .allocattr = hpcfb_allocattr, 231 .replaceattr = NULL, 232 }; 233 234 /* 235 * static variables 236 */ 237 CFATTACH_DECL(hpcfb, sizeof(struct hpcfb_softc), 238 hpcfbmatch, hpcfbattach, NULL, NULL); 239 240 struct wsscreen_descr hpcfb_stdscreen = { 241 .name = "std", 242 .textops = &hpcfb_emulops, /* XXX */ 243 .capabilities = WSSCREEN_REVERSE, 244 /* XXX: ncols/nrows will be filled in -- shouldn't, they are global */ 245 }; 246 247 const struct wsscreen_descr *_hpcfb_scrlist[] = { 248 &hpcfb_stdscreen, 249 /* XXX other formats, graphics screen? */ 250 }; 251 252 struct wsscreen_list hpcfb_screenlist = { 253 .nscreens = __arraycount(_hpcfb_scrlist), 254 .screens = _hpcfb_scrlist, 255 }; 256 257 struct wsdisplay_accessops hpcfb_accessops = { 258 .ioctl = hpcfb_ioctl, 259 .mmap = hpcfb_mmap, 260 .alloc_screen = hpcfb_alloc_screen, 261 .free_screen = hpcfb_free_screen, 262 .show_screen = hpcfb_show_screen, 263 .load_font = NULL, 264 .pollc = hpcfb_pollc, 265 .scroll = NULL, 266 }; 267 268 void hpcfb_tv_putchar(struct hpcfb_devconfig *, int, int, u_int, long); 269 void hpcfb_tv_copycols(struct hpcfb_devconfig *, int, int, int, int); 270 void hpcfb_tv_erasecols(struct hpcfb_devconfig *, int, int, int, long); 271 void hpcfb_tv_copyrows(struct hpcfb_devconfig *, int, int, int); 272 void hpcfb_tv_eraserows(struct hpcfb_devconfig *, int, int, long); 273 274 struct wsdisplay_emulops rasops_emul; 275 276 static int hpcfbconsole; 277 struct hpcfb_devconfig hpcfb_console_dc; 278 struct wsscreen_descr hpcfb_console_wsscreen; 279 struct hpcfb_tvrow hpcfb_console_tvram[HPCFB_MAX_ROW]; 280 281 /* 282 * function bodies 283 */ 284 285 int 286 hpcfbmatch(struct device *parent, 287 struct cfdata *match, void *aux) 288 { 289 return (1); 290 } 291 292 void 293 hpcfbattach(struct device *parent, 294 struct device *self, void *aux) 295 { 296 struct hpcfb_softc *sc = device_private(self); 297 struct hpcfb_attach_args *ha = aux; 298 struct wsemuldisplaydev_attach_args wa; 299 300 sc->sc_accessops = ha->ha_accessops; 301 sc->sc_accessctx = ha->ha_accessctx; 302 sc->sc_nfbconf = ha->ha_nfbconf; 303 sc->sc_fbconflist = ha->ha_fbconflist; 304 305 if (hpcfbconsole) { 306 sc->sc_dc = &hpcfb_console_dc; 307 hpcfb_console_dc.dc_sc = sc; 308 printf(": %dx%d pixels, %d colors, %dx%d chars", 309 sc->sc_dc->dc_rinfo.ri_width,sc->sc_dc->dc_rinfo.ri_height, 310 (1 << sc->sc_dc->dc_rinfo.ri_depth), 311 sc->sc_dc->dc_rinfo.ri_cols,sc->sc_dc->dc_rinfo.ri_rows); 312 /* Set video chip dependent CLUT if any. */ 313 if (sc->sc_accessops->setclut) 314 sc->sc_accessops->setclut(sc->sc_accessctx, 315 &hpcfb_console_dc.dc_rinfo); 316 } 317 printf("\n"); 318 319 sc->sc_polling = 0; /* XXX */ 320 sc->sc_mapping = 0; /* XXX */ 321 callout_init(&sc->sc_switch_callout); 322 323 /* Add a power hook to power management */ 324 sc->sc_powerhook = powerhook_establish(sc->sc_dev.dv_xname, 325 hpcfb_power, sc); 326 if (sc->sc_powerhook == NULL) 327 printf("%s: WARNING: unable to establish power hook\n", 328 sc->sc_dev.dv_xname); 329 330 wa.console = hpcfbconsole; 331 wa.scrdata = &hpcfb_screenlist; 332 wa.accessops = &hpcfb_accessops; 333 wa.accesscookie = sc; 334 335 sc->sc_wsdisplay = config_found(self, &wa, wsemuldisplaydevprint); 336 337 #ifdef HPCFB_JUMP 338 /* 339 * Create a kernel thread to scroll, 340 */ 341 kthread_create(hpcfb_create_thread, sc); 342 #endif /* HPCFB_JUMP */ 343 } 344 345 #ifdef HPCFB_JUMP 346 void 347 hpcfb_create_thread(void *arg) 348 { 349 struct hpcfb_softc *sc = arg; 350 351 if (kthread_create1(hpcfb_thread, sc, &sc->sc_thread, 352 "%s", sc->sc_dev.dv_xname) == 0) 353 return; 354 355 /* 356 * We were unable to create the HPCFB thread; bail out. 357 */ 358 sc->sc_thread = 0; 359 printf("%s: unable to create thread, kernel hpcfb scroll support disabled\n", 360 sc->sc_dev.dv_xname); 361 } 362 363 void 364 hpcfb_thread(void *arg) 365 { 366 struct hpcfb_softc *sc = arg; 367 368 /* 369 * Loop forever, doing a periodic check for update events. 370 */ 371 for (;;) { 372 /* HPCFB_LOCK(sc); */ 373 sc->sc_dc->dc_state |= HPCFB_DC_SCRTHREAD; 374 if (!sc->sc_mapping) /* draw only EMUL mode */ 375 hpcfb_update(sc->sc_dc); 376 sc->sc_dc->dc_state &= ~HPCFB_DC_SCRTHREAD; 377 /* APM_UNLOCK(sc); */ 378 (void) tsleep(sc, PWAIT, "hpcfb", (8 * hz) / 7 / 10); 379 } 380 } 381 #endif /* HPCFB_JUMP */ 382 383 /* Print function (for parent devices). */ 384 int 385 hpcfbprint(void *aux, const char *pnp) 386 { 387 if (pnp) 388 aprint_normal("hpcfb at %s", pnp); 389 390 return (UNCONF); 391 } 392 393 int 394 hpcfb_cnattach(struct hpcfb_fbconf *fbconf) 395 { 396 #if NBIVIDEO > 0 397 struct hpcfb_fbconf __fbconf; 398 #endif 399 long defattr; 400 401 DPRINTF(("%s(%d): hpcfb_cnattach()\n", __FILE__, __LINE__)); 402 #if NBIVIDEO > 0 403 if (fbconf == NULL) { 404 memset(&__fbconf, 0, sizeof(struct hpcfb_fbconf)); 405 if (bivideo_getcnfb(&__fbconf) != 0) 406 return (ENXIO); 407 fbconf = &__fbconf; 408 } 409 #endif /* NBIVIDEO > 0 */ 410 memset(&hpcfb_console_dc, 0, sizeof(struct hpcfb_devconfig)); 411 if (hpcfb_init(fbconf, &hpcfb_console_dc) != 0) 412 return (ENXIO); 413 hpcfb_console_dc.dc_state |= HPCFB_DC_CURRENT; 414 415 hpcfb_console_dc.dc_tvram = hpcfb_console_tvram; 416 /* clear screen */ 417 memset(hpcfb_console_tvram, 0, sizeof(hpcfb_console_tvram)); 418 hpcfb_redraw(&hpcfb_console_dc, 0, hpcfb_console_dc.dc_rows, 1); 419 420 hpcfb_console_wsscreen = hpcfb_stdscreen; 421 hpcfb_console_wsscreen.nrows = hpcfb_console_dc.dc_rows; 422 hpcfb_console_wsscreen.ncols = hpcfb_console_dc.dc_cols; 423 hpcfb_console_wsscreen.capabilities = hpcfb_console_dc.dc_rinfo.ri_caps; 424 hpcfb_allocattr(&hpcfb_console_dc, 425 WSCOL_WHITE, WSCOL_BLACK, 0, &defattr); 426 wsdisplay_cnattach(&hpcfb_console_wsscreen, &hpcfb_console_dc, 427 0, 0, defattr); 428 hpcfbconsole = 1; 429 430 return (0); 431 } 432 433 int 434 hpcfb_init(struct hpcfb_fbconf *fbconf, struct hpcfb_devconfig *dc) 435 { 436 struct rasops_info *ri; 437 vaddr_t fbaddr; 438 439 fbaddr = (vaddr_t)fbconf->hf_baseaddr; 440 dc->dc_fbaddr = (u_char *)fbaddr; 441 442 /* init rasops */ 443 ri = &dc->dc_rinfo; 444 memset(ri, 0, sizeof(struct rasops_info)); 445 ri->ri_depth = fbconf->hf_pixel_width; 446 ri->ri_bits = (void *)fbaddr; 447 ri->ri_width = fbconf->hf_width; 448 ri->ri_height = fbconf->hf_height; 449 ri->ri_stride = fbconf->hf_bytes_per_line; 450 #if 0 451 ri->ri_flg = RI_FORCEMONO | RI_CURSOR; 452 #else 453 ri->ri_flg = RI_CURSOR; 454 #endif 455 switch (ri->ri_depth) { 456 case 8: 457 if (32 <= fbconf->hf_pack_width && 458 (fbconf->hf_order_flags & HPCFB_REVORDER_BYTE) && 459 (fbconf->hf_order_flags & HPCFB_REVORDER_WORD)) { 460 ri->ri_flg |= RI_BSWAP; 461 } 462 break; 463 default: 464 if (fbconf->hf_order_flags & HPCFB_REVORDER_BYTE) { 465 #if BYTE_ORDER == BIG_ENDIAN 466 ri->ri_flg |= RI_BSWAP; 467 #endif 468 } else { 469 #if BYTE_ORDER == LITTLE_ENDIAN 470 ri->ri_flg |= RI_BSWAP; 471 #endif 472 } 473 break; 474 } 475 476 if (fbconf->hf_class == HPCFB_CLASS_RGBCOLOR) { 477 ri->ri_rnum = fbconf->hf_u.hf_rgb.hf_red_width; 478 ri->ri_rpos = fbconf->hf_u.hf_rgb.hf_red_shift; 479 ri->ri_gnum = fbconf->hf_u.hf_rgb.hf_green_width; 480 ri->ri_gpos = fbconf->hf_u.hf_rgb.hf_green_shift; 481 ri->ri_bnum = fbconf->hf_u.hf_rgb.hf_blue_width; 482 ri->ri_bpos = fbconf->hf_u.hf_rgb.hf_blue_shift; 483 } 484 485 if (rasops_init(ri, HPCFB_MAX_ROW, HPCFB_MAX_COLUMN)) { 486 panic("%s(%d): rasops_init() failed!", __FILE__, __LINE__); 487 } 488 489 /* over write color map of rasops */ 490 hpcfb_cmap_reorder (fbconf, dc); 491 492 dc->dc_curx = -1; 493 dc->dc_cury = -1; 494 dc->dc_rows = dc->dc_rinfo.ri_rows; 495 dc->dc_cols = dc->dc_rinfo.ri_cols; 496 #ifdef HPCFB_JUMP 497 dc->dc_max_row = 0; 498 dc->dc_min_row = dc->dc_rows; 499 dc->dc_scroll = 0; 500 callout_init(&dc->dc_scroll_ch); 501 #endif /* HPCFB_JUMP */ 502 dc->dc_memsize = ri->ri_stride * ri->ri_height; 503 /* hook rasops in hpcfb_ops */ 504 rasops_emul = ri->ri_ops; /* struct copy */ 505 ri->ri_ops = hpcfb_emulops; /* struct copy */ 506 507 return (0); 508 } 509 510 static void 511 hpcfb_cmap_reorder(struct hpcfb_fbconf *fbconf, struct hpcfb_devconfig *dc) 512 { 513 struct rasops_info *ri = &dc->dc_rinfo; 514 int reverse = fbconf->hf_access_flags & HPCFB_ACCESS_REVERSE; 515 int *cmap = ri->ri_devcmap; 516 int i, j, bg, fg, tmp; 517 518 /* 519 * Set forground and background so that the screen 520 * looks black on white. 521 * Normally, black = 00 and white = ff. 522 * HPCFB_ACCESS_REVERSE means black = ff and white = 00. 523 */ 524 switch (fbconf->hf_pixel_width) { 525 case 1: 526 /* FALLTHROUGH */ 527 case 2: 528 /* FALLTHROUGH */ 529 case 4: 530 if (reverse) { 531 bg = 0; 532 fg = ~0; 533 } else { 534 bg = ~0; 535 fg = 0; 536 } 537 /* for gray-scale LCD, hi-contrast color map */ 538 cmap[0] = bg; 539 for (i = 1; i < 16; i++) 540 cmap[i] = fg; 541 break; 542 case 8: 543 /* FALLTHROUGH */ 544 case 16: 545 if (reverse) { 546 for (i = 0, j = 15; i < 8; i++, j--) { 547 tmp = cmap[i]; 548 cmap[i] = cmap[j]; 549 cmap[j] = tmp; 550 } 551 } 552 break; 553 } 554 } 555 556 int 557 hpcfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 558 struct lwp *l) 559 { 560 struct hpcfb_softc *sc = v; 561 struct hpcfb_devconfig *dc = sc->sc_dc; 562 struct wsdisplay_fbinfo *wdf; 563 564 DPRINTF(("hpcfb_ioctl(cmd=0x%lx)\n", cmd)); 565 switch (cmd) { 566 case WSKBDIO_BELL: 567 return (0); 568 break; 569 570 case WSDISPLAYIO_GTYPE: 571 *(u_int *)data = WSDISPLAY_TYPE_HPCFB; 572 return (0); 573 574 case WSDISPLAYIO_GINFO: 575 wdf = (void *)data; 576 wdf->height = dc->dc_rinfo.ri_height; 577 wdf->width = dc->dc_rinfo.ri_width; 578 wdf->depth = dc->dc_rinfo.ri_depth; 579 wdf->cmsize = 256; /* XXXX */ 580 return (0); 581 582 case WSDISPLAYIO_SMODE: 583 if (*(int *)data == WSDISPLAYIO_MODE_EMUL){ 584 if (sc->sc_mapping){ 585 sc->sc_mapping = 0; 586 if (dc->dc_state&HPCFB_DC_DRAWING) 587 dc->dc_state &= ~HPCFB_DC_ABORT; 588 #ifdef HPCFB_FORCE_REDRAW 589 hpcfb_refresh_screen(sc); 590 #else 591 dc->dc_state |= HPCFB_DC_UPDATEALL; 592 #endif 593 } 594 } else { 595 if (!sc->sc_mapping) { 596 sc->sc_mapping = 1; 597 dc->dc_state |= HPCFB_DC_ABORT; 598 } 599 sc->sc_mapping = 1; 600 } 601 if (sc && sc->sc_accessops->iodone) 602 (*sc->sc_accessops->iodone)(sc->sc_accessctx); 603 return (0); 604 605 case WSDISPLAYIO_GETCMAP: 606 case WSDISPLAYIO_PUTCMAP: 607 case WSDISPLAYIO_SVIDEO: 608 case WSDISPLAYIO_GVIDEO: 609 case WSDISPLAYIO_GETPARAM: 610 case WSDISPLAYIO_SETPARAM: 611 case HPCFBIO_GCONF: 612 case HPCFBIO_SCONF: 613 case HPCFBIO_GDSPCONF: 614 case HPCFBIO_SDSPCONF: 615 case HPCFBIO_GOP: 616 case HPCFBIO_SOP: 617 return ((*sc->sc_accessops->ioctl)(sc->sc_accessctx, 618 cmd, data, flag, l)); 619 620 default: 621 if (IOCGROUP(cmd) != 't') 622 DPRINTF(("%s(%d): hpcfb_ioctl(%lx, %lx) grp=%c num=%ld\n", 623 __FILE__, __LINE__, 624 cmd, (u_long)data, (char)IOCGROUP(cmd), cmd&0xff)); 625 break; 626 } 627 628 return (EPASSTHROUGH); /* Inappropriate ioctl for device */ 629 } 630 631 paddr_t 632 hpcfb_mmap(void *v, void *vs, off_t offset, int prot) 633 { 634 struct hpcfb_softc *sc = v; 635 636 return ((*sc->sc_accessops->mmap)(sc->sc_accessctx, offset, prot)); 637 } 638 639 static void 640 hpcfb_power(int why, void *arg) 641 { 642 struct hpcfb_softc *sc = arg; 643 644 if (sc->sc_dc == NULL) 645 return; /* You have no screen yet. */ 646 647 switch (why) { 648 case PWR_STANDBY: 649 break; 650 case PWR_SOFTSUSPEND: 651 /* XXX, casting to 'struct wsdisplay_softc *' means 652 that you should not call the method here... */ 653 sc->sc_screen_resumed = wsdisplay_getactivescreen( 654 (struct wsdisplay_softc *)sc->sc_wsdisplay); 655 if (wsdisplay_switch(sc->sc_wsdisplay, 656 WSDISPLAY_NULLSCREEN, 657 1 /* waitok */) == 0) { 658 wsscreen_switchwait( 659 (struct wsdisplay_softc *)sc->sc_wsdisplay, 660 WSDISPLAY_NULLSCREEN); 661 } else { 662 sc->sc_screen_resumed = WSDISPLAY_NULLSCREEN; 663 } 664 665 sc->sc_dc->dc_state &= ~HPCFB_DC_CURRENT; 666 break; 667 case PWR_SOFTRESUME: 668 sc->sc_dc->dc_state |= HPCFB_DC_CURRENT; 669 if (sc->sc_screen_resumed != WSDISPLAY_NULLSCREEN) 670 wsdisplay_switch(sc->sc_wsdisplay, 671 sc->sc_screen_resumed, 672 1 /* waitok */); 673 break; 674 } 675 } 676 677 void 678 hpcfb_refresh_screen(struct hpcfb_softc *sc) 679 { 680 struct hpcfb_devconfig *dc = sc->sc_dc; 681 int x, y; 682 683 DPRINTF(("hpcfb_refres_screen()\n")); 684 if (dc == NULL) 685 return; 686 687 #ifdef HPCFB_JUMP 688 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 689 dc->dc_state &= ~HPCFB_DC_SCROLLPENDING; 690 dc->dc_state &= ~HPCFB_DC_UPDATE; 691 callout_stop(&dc->dc_scroll_ch); 692 } 693 #endif /* HPCFB_JUMP */ 694 /* 695 * refresh screen 696 */ 697 dc->dc_state &= ~HPCFB_DC_UPDATEALL; 698 x = dc->dc_curx; 699 y = dc->dc_cury; 700 if (0 <= x && 0 <= y) 701 hpcfb_cursor_raw(dc, 0, y, x); /* disable cursor */ 702 /* redraw all text */ 703 hpcfb_redraw(dc, 0, dc->dc_rows, 1); 704 if (0 <= x && 0 <= y) 705 hpcfb_cursor_raw(dc, 1, y, x); /* enable cursor */ 706 } 707 708 static int 709 hpcfb_alloc_screen(void *v, const struct wsscreen_descr *type, 710 void **cookiep, int *curxp, int *curyp, long *attrp) 711 { 712 struct hpcfb_softc *sc = v; 713 struct hpcfb_devconfig *dc; 714 715 DPRINTF(("%s(%d): hpcfb_alloc_screen()\n", __FILE__, __LINE__)); 716 717 dc = malloc(sizeof(struct hpcfb_devconfig), M_DEVBUF, M_WAITOK|M_ZERO); 718 if (dc == NULL) 719 return (ENOMEM); 720 721 dc->dc_sc = sc; 722 if (hpcfb_init(&sc->sc_fbconflist[0], dc) != 0) 723 return (EINVAL); 724 if (sc->sc_accessops->font) { 725 sc->sc_accessops->font(sc->sc_accessctx, 726 dc->dc_rinfo.ri_font); 727 } 728 /* Set video chip dependent CLUT if any. */ 729 if (sc->sc_accessops->setclut) 730 sc->sc_accessops->setclut(sc->sc_accessctx, &dc->dc_rinfo); 731 printf("hpcfb: %dx%d pixels, %d colors, %dx%d chars\n", 732 dc->dc_rinfo.ri_width, dc->dc_rinfo.ri_height, 733 (1 << dc->dc_rinfo.ri_depth), 734 dc->dc_rinfo.ri_cols, dc->dc_rinfo.ri_rows); 735 736 /* 737 * XXX, wsdisplay won't reffer the information in wsscreen_descr 738 * structure until alloc_screen will be called, at least, under 739 * current implementation... 740 */ 741 hpcfb_stdscreen.nrows = dc->dc_rows; 742 hpcfb_stdscreen.ncols = dc->dc_cols; 743 hpcfb_stdscreen.capabilities = dc->dc_rinfo.ri_caps; 744 745 dc->dc_fbaddr = dc->dc_rinfo.ri_bits; 746 dc->dc_rows = dc->dc_rinfo.ri_rows; 747 dc->dc_cols = dc->dc_rinfo.ri_cols; 748 dc->dc_memsize = dc->dc_rinfo.ri_stride * dc->dc_rinfo.ri_height; 749 750 dc->dc_curx = -1; 751 dc->dc_cury = -1; 752 dc->dc_tvram = malloc(sizeof(struct hpcfb_tvrow)*dc->dc_rows, 753 M_DEVBUF, M_WAITOK|M_ZERO); 754 if (dc->dc_tvram == NULL){ 755 free(dc, M_DEVBUF); 756 return (ENOMEM); 757 } 758 759 *curxp = 0; 760 *curyp = 0; 761 *cookiep = dc; 762 hpcfb_allocattr(*cookiep, WSCOL_WHITE, WSCOL_BLACK, 0, attrp); 763 DPRINTF(("%s(%d): hpcfb_alloc_screen(): %p\n", 764 __FILE__, __LINE__, dc)); 765 766 return (0); 767 } 768 769 static void 770 hpcfb_free_screen(void *v, void *cookie) 771 { 772 struct hpcfb_devconfig *dc = cookie; 773 774 DPRINTF(("%s(%d): hpcfb_free_screen(%p)\n", 775 __FILE__, __LINE__, cookie)); 776 #ifdef DIAGNOSTIC 777 if (dc == &hpcfb_console_dc) 778 panic("hpcfb_free_screen: console"); 779 #endif 780 free(dc->dc_tvram, M_DEVBUF); 781 free(dc, M_DEVBUF); 782 } 783 784 static int 785 hpcfb_show_screen(void *v, void *cookie, int waitok, 786 void (*cb)(void *, int, int), void *cbarg) 787 { 788 struct hpcfb_softc *sc = v; 789 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 790 struct hpcfb_devconfig *odc; 791 792 DPRINTF(("%s(%d): hpcfb_show_screen(%p)\n", 793 __FILE__, __LINE__, dc)); 794 795 odc = sc->sc_dc; 796 797 if (dc == NULL || odc == dc) { 798 hpcfb_refresh_screen(sc); 799 return (0); 800 } 801 802 if (odc != NULL) { 803 odc->dc_state |= HPCFB_DC_SWITCHREQ; 804 805 if ((odc->dc_state&HPCFB_DC_DRAWING) != 0) { 806 odc->dc_state |= HPCFB_DC_ABORT; 807 } 808 } 809 810 sc->sc_wantedscreen = cookie; 811 sc->sc_switchcb = cb; 812 sc->sc_switchcbarg = cbarg; 813 if (cb) { 814 callout_reset(&sc->sc_switch_callout, 0, 815 (void(*)(void *))hpcfb_doswitch, sc); 816 return (EAGAIN); 817 } 818 819 hpcfb_doswitch(sc); 820 return (0); 821 } 822 823 void 824 hpcfb_doswitch(struct hpcfb_softc *sc) 825 { 826 struct hpcfb_devconfig *dc; 827 struct hpcfb_devconfig *odc; 828 829 DPRINTF(("hpcfb_doswitch()\n")); 830 odc = sc->sc_dc; 831 dc = sc->sc_wantedscreen; 832 833 if (!dc) { 834 (*sc->sc_switchcb)(sc->sc_switchcbarg, EIO, 0); 835 odc->dc_state &= ~HPCFB_DC_SWITCHREQ; 836 return; 837 } 838 839 if (odc == dc) { 840 odc->dc_state &= ~HPCFB_DC_SWITCHREQ; 841 return; 842 } 843 844 if (odc) { 845 #ifdef HPCFB_JUMP 846 odc->dc_state |= HPCFB_DC_ABORT; 847 #endif /* HPCFB_JUMP */ 848 849 if (odc->dc_curx >= 0 && odc->dc_cury >= 0) 850 hpcfb_cursor_raw(odc, 0, odc->dc_cury, odc->dc_curx); 851 /* disable cursor */ 852 /* disable old screen */ 853 odc->dc_state &= ~HPCFB_DC_CURRENT; 854 /* XXX, This is too dangerous. 855 odc->dc_rinfo.ri_bits = NULL; 856 */ 857 } 858 /* switch screen to new one */ 859 dc->dc_state |= HPCFB_DC_CURRENT; 860 dc->dc_state &= ~HPCFB_DC_ABORT; 861 dc->dc_rinfo.ri_bits = dc->dc_fbaddr; 862 sc->sc_dc = dc; 863 864 /* redraw screen image */ 865 hpcfb_refresh_screen(sc); 866 867 sc->sc_wantedscreen = NULL; 868 if (sc->sc_switchcb) 869 (*sc->sc_switchcb)(sc->sc_switchcbarg, 0, 0); 870 871 if (odc != NULL) 872 odc->dc_state &= ~HPCFB_DC_SWITCHREQ; 873 dc->dc_state &= ~HPCFB_DC_SWITCHREQ; 874 return; 875 } 876 877 static void 878 hpcfb_pollc(void *v, int on) 879 { 880 struct hpcfb_softc *sc = v; 881 882 if (sc == NULL) 883 return; 884 sc->sc_polling = on; 885 if (sc->sc_accessops->iodone) 886 (*sc->sc_accessops->iodone)(sc->sc_accessctx); 887 if (on) { 888 hpcfb_refresh_screen(sc); 889 if (sc->sc_accessops->iodone) 890 (*sc->sc_accessops->iodone)(sc->sc_accessctx); 891 } 892 893 return; 894 } 895 896 /* 897 * cursor 898 */ 899 void 900 hpcfb_cursor(void *cookie, int on, int row, int col) 901 { 902 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 903 904 if (on) { 905 dc->dc_curx = col; 906 dc->dc_cury = row; 907 } else { 908 dc->dc_curx = -1; 909 dc->dc_cury = -1; 910 } 911 912 hpcfb_cursor_raw(cookie, on, row, col); 913 } 914 915 void 916 hpcfb_cursor_raw(cookie, on, row, col) 917 void *cookie; 918 int on, row, col; 919 { 920 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 921 struct hpcfb_softc *sc = dc->dc_sc; 922 struct rasops_info *ri = &dc->dc_rinfo; 923 int curwidth, curheight; 924 int xoff, yoff; 925 926 #ifdef HPCFB_JUMP 927 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 928 dc->dc_state |= HPCFB_DC_UPDATE; 929 return; 930 } 931 #endif /* HPCFB_JUMP */ 932 if (!IS_DRAWABLE(dc)) { 933 return; 934 } 935 936 if (ri->ri_bits == NULL) 937 return; 938 939 dc->dc_state |= HPCFB_DC_DRAWING; 940 if (sc && sc->sc_accessops->cursor) { 941 xoff = col * ri->ri_font->fontwidth; 942 yoff = row * ri->ri_font->fontheight; 943 curheight = ri->ri_font->fontheight; 944 curwidth = ri->ri_font->fontwidth; 945 (*sc->sc_accessops->cursor)(sc->sc_accessctx, 946 on, xoff, yoff, curwidth, curheight); 947 } else 948 rasops_emul.cursor(ri, on, row, col); 949 dc->dc_state &= ~HPCFB_DC_DRAWING; 950 } 951 952 /* 953 * mapchar 954 */ 955 int 956 hpcfb_mapchar(void *cookie, int c, unsigned int *cp) 957 { 958 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 959 struct rasops_info *ri = &dc->dc_rinfo; 960 961 return (rasops_emul.mapchar(ri, c, cp)); 962 } 963 964 /* 965 * putchar 966 */ 967 void 968 hpcfb_tv_putchar(struct hpcfb_devconfig *dc, int row, int col, u_int uc, 969 long attr) 970 { 971 struct hpcfb_tvrow *vscn = dc->dc_tvram; 972 struct hpcfb_vchar *vc = &vscn[row].col[col]; 973 struct hpcfb_vchar *vcb; 974 975 if (vscn == 0) 976 return; 977 978 dc->dc_state |= HPCFB_DC_TDRAWING; 979 #ifdef HPCFB_JUMP 980 if (row < dc->dc_min_row) 981 dc->dc_min_row = row; 982 if (row > dc->dc_max_row) 983 dc->dc_max_row = row; 984 985 #endif /* HPCFB_JUMP */ 986 if (vscn[row].maxcol +1 == col) 987 vscn[row].maxcol = col; 988 else if (vscn[row].maxcol < col) { 989 vcb = &vscn[row].col[vscn[row].maxcol+1]; 990 memset(vcb, 0, 991 sizeof(struct hpcfb_vchar)*(col-vscn[row].maxcol-1)); 992 vscn[row].maxcol = col; 993 } 994 vc->c = uc; 995 vc->attr = attr; 996 dc->dc_state &= ~HPCFB_DC_TDRAWING; 997 #ifdef HPCFB_JUMP 998 hpcfb_check_update(dc); 999 #endif /* HPCFB_JUMP */ 1000 } 1001 1002 void 1003 hpcfb_putchar(void *cookie, int row, int col, u_int uc, long attr) 1004 { 1005 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1006 struct hpcfb_softc *sc = dc->dc_sc; 1007 struct rasops_info *ri = &dc->dc_rinfo; 1008 int xoff; 1009 int yoff; 1010 int fclr, uclr; 1011 struct wsdisplay_font *font; 1012 1013 hpcfb_tv_putchar(dc, row, col, uc, attr); 1014 #ifdef HPCFB_JUMP 1015 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1016 dc->dc_state |= HPCFB_DC_UPDATE; 1017 return; 1018 } 1019 #endif /* HPCFB_JUMP */ 1020 1021 if (!IS_DRAWABLE(dc)) { 1022 return; 1023 } 1024 1025 if (ri->ri_bits == NULL) 1026 return; 1027 1028 dc->dc_state |= HPCFB_DC_DRAWING; 1029 if (sc && sc->sc_accessops->putchar 1030 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1031 font = ri->ri_font; 1032 yoff = row * ri->ri_font->fontheight; 1033 xoff = col * ri->ri_font->fontwidth; 1034 fclr = ri->ri_devcmap[((u_int)attr >> 24) & 15]; 1035 uclr = ri->ri_devcmap[((u_int)attr >> 16) & 15]; 1036 1037 (*sc->sc_accessops->putchar)(sc->sc_accessctx, 1038 xoff, yoff, font, fclr, uclr, uc, attr); 1039 } else 1040 rasops_emul.putchar(ri, row, col, uc, attr); 1041 dc->dc_state &= ~HPCFB_DC_DRAWING; 1042 #ifdef HPCFB_JUMP 1043 hpcfb_check_update(dc); 1044 #endif /* HPCFB_JUMP */ 1045 } 1046 1047 /* 1048 * copycols 1049 */ 1050 void 1051 hpcfb_tv_copycols(struct hpcfb_devconfig *dc, int row, int srccol, int dstcol, 1052 int ncols) 1053 { 1054 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1055 struct hpcfb_vchar *svc = &vscn[row].col[srccol]; 1056 struct hpcfb_vchar *dvc = &vscn[row].col[dstcol]; 1057 1058 if (vscn == 0) 1059 return; 1060 1061 dc->dc_state |= HPCFB_DC_TDRAWING; 1062 #ifdef HPCFB_JUMP 1063 if (row < dc->dc_min_row) 1064 dc->dc_min_row = row; 1065 if (row > dc->dc_max_row) 1066 dc->dc_max_row = row; 1067 #endif /* HPCFB_JUMP */ 1068 1069 memcpy(dvc, svc, ncols*sizeof(struct hpcfb_vchar)); 1070 if (vscn[row].maxcol < srccol+ncols-1) 1071 vscn[row].maxcol = srccol+ncols-1; 1072 if (vscn[row].maxcol < dstcol+ncols-1) 1073 vscn[row].maxcol = dstcol+ncols-1; 1074 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1075 #ifdef HPCFB_JUMP 1076 hpcfb_check_update(dc); 1077 #endif /* HPCFB_JUMP */ 1078 } 1079 1080 void 1081 hpcfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1082 { 1083 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1084 struct hpcfb_softc *sc = dc->dc_sc; 1085 struct rasops_info *ri = &dc->dc_rinfo; 1086 int srcxoff,dstxoff; 1087 int srcyoff,dstyoff; 1088 int height, width; 1089 1090 hpcfb_tv_copycols(dc, row, srccol, dstcol, ncols); 1091 #ifdef HPCFB_JUMP 1092 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1093 dc->dc_state |= HPCFB_DC_UPDATE; 1094 return; 1095 } 1096 #endif /* HPCFB_JUMP */ 1097 if (!IS_DRAWABLE(dc)) { 1098 return; 1099 } 1100 1101 if (ri->ri_bits == NULL) 1102 return; 1103 1104 dc->dc_state |= HPCFB_DC_DRAWING; 1105 if (sc && sc->sc_accessops->bitblit 1106 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1107 srcxoff = srccol * ri->ri_font->fontwidth; 1108 srcyoff = row * ri->ri_font->fontheight; 1109 dstxoff = dstcol * ri->ri_font->fontwidth; 1110 dstyoff = row * ri->ri_font->fontheight; 1111 width = ncols * ri->ri_font->fontwidth; 1112 height = ri->ri_font->fontheight; 1113 (*sc->sc_accessops->bitblit)(sc->sc_accessctx, 1114 srcxoff, srcyoff, dstxoff, dstyoff, height, width); 1115 } else 1116 rasops_emul.copycols(ri, row, srccol, dstcol, ncols); 1117 dc->dc_state &= ~HPCFB_DC_DRAWING; 1118 #ifdef HPCFB_JUMP 1119 hpcfb_check_update(dc); 1120 #endif /* HPCFB_JUMP */ 1121 } 1122 1123 1124 /* 1125 * erasecols 1126 */ 1127 void 1128 hpcfb_tv_erasecols(struct hpcfb_devconfig *dc, 1129 int row, int startcol, int ncols, long attr) 1130 { 1131 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1132 1133 if (vscn == 0) 1134 return; 1135 1136 dc->dc_state |= HPCFB_DC_TDRAWING; 1137 #ifdef HPCFB_JUMP 1138 if (row < dc->dc_min_row) 1139 dc->dc_min_row = row; 1140 if (row > dc->dc_max_row) 1141 dc->dc_max_row = row; 1142 #endif /* HPCFB_JUMP */ 1143 1144 vscn[row].maxcol = startcol-1; 1145 if (vscn[row].spacecol < startcol+ncols-1) 1146 vscn[row].spacecol = startcol+ncols-1; 1147 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1148 #ifdef HPCFB_JUMP 1149 hpcfb_check_update(dc); 1150 #endif /* HPCFB_JUMP */ 1151 } 1152 1153 void 1154 hpcfb_erasecols(void *cookie, int row, int startcol, int ncols, long attr) 1155 { 1156 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1157 struct hpcfb_softc *sc = dc->dc_sc; 1158 struct rasops_info *ri = &dc->dc_rinfo; 1159 int xoff, yoff; 1160 int width, height; 1161 1162 hpcfb_tv_erasecols(dc, row, startcol, ncols, attr); 1163 #ifdef HPCFB_JUMP 1164 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1165 dc->dc_state |= HPCFB_DC_UPDATE; 1166 return; 1167 } 1168 #endif /* HPCFB_JUMP */ 1169 if (!IS_DRAWABLE(dc)) { 1170 return; 1171 } 1172 1173 if (ri->ri_bits == NULL) 1174 return; 1175 1176 dc->dc_state |= HPCFB_DC_DRAWING; 1177 if (sc && sc->sc_accessops->erase 1178 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1179 xoff = startcol * ri->ri_font->fontwidth; 1180 yoff = row * ri->ri_font->fontheight; 1181 width = ncols * ri->ri_font->fontwidth; 1182 height = ri->ri_font->fontheight; 1183 (*sc->sc_accessops->erase)(sc->sc_accessctx, 1184 xoff, yoff, height, width, attr); 1185 } else 1186 rasops_emul.erasecols(ri, row, startcol, ncols, attr); 1187 dc->dc_state &= ~HPCFB_DC_DRAWING; 1188 #ifdef HPCFB_JUMP 1189 hpcfb_check_update(dc); 1190 #endif /* HPCFB_JUMP */ 1191 } 1192 1193 /* 1194 * Copy rows. 1195 */ 1196 void 1197 hpcfb_tv_copyrows(struct hpcfb_devconfig *dc, int src, int dst, int num) 1198 { 1199 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1200 struct hpcfb_tvrow *svc = &vscn[src]; 1201 struct hpcfb_tvrow *dvc = &vscn[dst]; 1202 int i; 1203 int d; 1204 1205 if (vscn == 0) 1206 return; 1207 1208 dc->dc_state |= HPCFB_DC_TDRAWING; 1209 #ifdef HPCFB_JUMP 1210 if (dst < dc->dc_min_row) 1211 dc->dc_min_row = dst; 1212 if (dst + num > dc->dc_max_row) 1213 dc->dc_max_row = dst + num -1; 1214 #endif /* HPCFB_JUMP */ 1215 1216 if (svc > dvc) 1217 d = 1; 1218 else if (svc < dvc) { 1219 svc += num-1; 1220 dvc += num-1; 1221 d = -1; 1222 } else { 1223 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1224 #ifdef HPCFB_JUMP 1225 hpcfb_check_update(dc); 1226 #endif /* HPCFB_JUMP */ 1227 return; 1228 } 1229 1230 for (i = 0; i < num; i++) { 1231 memcpy(&dvc->col[0], &svc->col[0], sizeof(struct hpcfb_vchar)*(svc->maxcol+1)); 1232 if (svc->maxcol < dvc->maxcol && dvc->spacecol < dvc->maxcol) 1233 dvc->spacecol = dvc->maxcol; 1234 dvc->maxcol = svc->maxcol; 1235 svc+=d; 1236 dvc+=d; 1237 } 1238 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1239 #ifdef HPCFB_JUMP 1240 hpcfb_check_update(dc); 1241 #endif /* HPCFB_JUMP */ 1242 } 1243 1244 void 1245 hpcfb_redraw(cookie, row, num, all) 1246 void *cookie; 1247 int row, num; 1248 int all; 1249 { 1250 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1251 struct rasops_info *ri = &dc->dc_rinfo; 1252 int cols; 1253 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1254 struct hpcfb_vchar *svc; 1255 int i, j; 1256 1257 #ifdef HPCFB_JUMP 1258 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1259 dc->dc_state |= HPCFB_DC_UPDATE; 1260 return; 1261 } 1262 #endif /* HPCFB_JUMP */ 1263 if (dc->dc_sc != NULL 1264 && !dc->dc_sc->sc_polling 1265 && dc->dc_sc->sc_mapping) 1266 return; 1267 1268 dc->dc_state &= ~HPCFB_DC_ABORT; 1269 1270 if (vscn == 0) 1271 return; 1272 1273 if (!IS_DRAWABLE(dc)) { 1274 return; 1275 } 1276 1277 if (ri->ri_bits == NULL) 1278 return; 1279 1280 dc->dc_state |= HPCFB_DC_DRAWING; 1281 dc->dc_state |= HPCFB_DC_TDRAWING; 1282 for (i = 0; i < num; i++) { 1283 if (dc->dc_state&HPCFB_DC_ABORT) 1284 break; 1285 if ((dc->dc_state&HPCFB_DC_CURRENT) == 0) 1286 break; 1287 cols = vscn[row+i].maxcol; 1288 for (j = 0; j <= cols; j++) { 1289 if (dc->dc_state&HPCFB_DC_ABORT) 1290 continue; 1291 if ((dc->dc_state&HPCFB_DC_CURRENT) == 0) 1292 continue; 1293 svc = &vscn[row+i].col[j]; 1294 rasops_emul.putchar(ri, row + i, j, svc->c, svc->attr); 1295 } 1296 if (all) 1297 cols = dc->dc_cols-1; 1298 else 1299 cols = vscn[row+i].spacecol; 1300 for (; j <= cols; j++) { 1301 if (dc->dc_state&HPCFB_DC_ABORT) 1302 continue; 1303 if ((dc->dc_state&HPCFB_DC_CURRENT) == 0) 1304 continue; 1305 rasops_emul.putchar(ri, row + i, j, ' ', 0); 1306 } 1307 vscn[row+i].spacecol = 0; 1308 } 1309 if (dc->dc_state&HPCFB_DC_ABORT) 1310 dc->dc_state &= ~HPCFB_DC_ABORT; 1311 dc->dc_state &= ~HPCFB_DC_DRAWING; 1312 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1313 #ifdef HPCFB_JUMP 1314 hpcfb_check_update(dc); 1315 #endif /* HPCFB_JUMP */ 1316 } 1317 1318 #ifdef HPCFB_JUMP 1319 void 1320 hpcfb_update(void *v) 1321 { 1322 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v; 1323 1324 /* callout_stop(&dc->dc_scroll_ch); */ 1325 dc->dc_state &= ~HPCFB_DC_SCROLLPENDING; 1326 if (dc->dc_curx > 0 && dc->dc_cury > 0) 1327 hpcfb_cursor_raw(dc, 0, dc->dc_cury, dc->dc_curx); 1328 if ((dc->dc_state&HPCFB_DC_UPDATEALL)) { 1329 hpcfb_redraw(dc, 0, dc->dc_rows, 1); 1330 dc->dc_state &= ~(HPCFB_DC_UPDATE|HPCFB_DC_UPDATEALL); 1331 } else if ((dc->dc_state&HPCFB_DC_UPDATE)) { 1332 hpcfb_redraw(dc, dc->dc_min_row, 1333 dc->dc_max_row - dc->dc_min_row, 0); 1334 dc->dc_state &= ~HPCFB_DC_UPDATE; 1335 } else { 1336 hpcfb_redraw(dc, dc->dc_scroll_dst, dc->dc_scroll_num, 0); 1337 } 1338 if (dc->dc_curx > 0 && dc->dc_cury > 0) 1339 hpcfb_cursor_raw(dc, 1, dc->dc_cury, dc->dc_curx); 1340 } 1341 1342 void 1343 hpcfb_do_scroll(void *v) 1344 { 1345 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v; 1346 1347 dc->dc_state |= HPCFB_DC_SCRTHREAD; 1348 if (dc->dc_state&(HPCFB_DC_DRAWING|HPCFB_DC_TDRAWING)) 1349 dc->dc_state |= HPCFB_DC_SCRDELAY; 1350 else if (dc->dc_sc != NULL && dc->dc_sc->sc_thread) 1351 wakeup(dc->dc_sc); 1352 else if (dc->dc_sc != NULL && !dc->dc_sc->sc_mapping) { 1353 /* draw only EMUL mode */ 1354 hpcfb_update(v); 1355 } 1356 dc->dc_state &= ~HPCFB_DC_SCRTHREAD; 1357 } 1358 1359 void 1360 hpcfb_check_update(void *v) 1361 { 1362 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v; 1363 1364 if (dc->dc_sc != NULL 1365 && dc->dc_sc->sc_polling 1366 && (dc->dc_state&HPCFB_DC_SCROLLPENDING)){ 1367 callout_stop(&dc->dc_scroll_ch); 1368 dc->dc_state &= ~HPCFB_DC_SCRDELAY; 1369 hpcfb_update(v); 1370 } 1371 else if (dc->dc_state&HPCFB_DC_SCRDELAY){ 1372 dc->dc_state &= ~HPCFB_DC_SCRDELAY; 1373 hpcfb_update(v); 1374 } else if (dc->dc_state&HPCFB_DC_UPDATEALL){ 1375 dc->dc_state &= ~HPCFB_DC_UPDATEALL; 1376 hpcfb_update(v); 1377 } 1378 } 1379 #endif /* HPCFB_JUMP */ 1380 1381 void 1382 hpcfb_copyrows(void *cookie, int src, int dst, int num) 1383 { 1384 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1385 struct rasops_info *ri = &dc->dc_rinfo; 1386 struct hpcfb_softc *sc = dc->dc_sc; 1387 int srcyoff, dstyoff; 1388 int width, height; 1389 1390 hpcfb_tv_copyrows(cookie, src, dst, num); 1391 1392 if (!IS_DRAWABLE(dc)) { 1393 return; 1394 } 1395 1396 if (ri->ri_bits == NULL) 1397 return; 1398 1399 if (sc && sc->sc_accessops->bitblit 1400 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1401 dc->dc_state |= HPCFB_DC_DRAWING; 1402 srcyoff = src * ri->ri_font->fontheight; 1403 dstyoff = dst * ri->ri_font->fontheight; 1404 width = dc->dc_cols * ri->ri_font->fontwidth; 1405 height = num * ri->ri_font->fontheight; 1406 (*sc->sc_accessops->bitblit)(sc->sc_accessctx, 1407 0, srcyoff, 0, dstyoff, height, width); 1408 dc->dc_state &= ~HPCFB_DC_DRAWING; 1409 } 1410 else { 1411 #ifdef HPCFB_JUMP 1412 if (sc && sc->sc_polling) { 1413 hpcfb_check_update(dc); 1414 } else if ((dc->dc_state&HPCFB_DC_SCROLLPENDING) == 0) { 1415 dc->dc_state |= HPCFB_DC_SCROLLPENDING; 1416 dc->dc_scroll = 1; 1417 dc->dc_scroll_src = src; 1418 dc->dc_scroll_dst = dst; 1419 dc->dc_scroll_num = num; 1420 callout_reset(&dc->dc_scroll_ch, hz/100, &hpcfb_do_scroll, dc); 1421 return; 1422 } else if (dc->dc_scroll++ < dc->dc_rows/HPCFB_MAX_JUMP) { 1423 dc->dc_state |= HPCFB_DC_UPDATE; 1424 return; 1425 } else { 1426 dc->dc_state &= ~HPCFB_DC_SCROLLPENDING; 1427 callout_stop(&dc->dc_scroll_ch); 1428 } 1429 if (dc->dc_state&HPCFB_DC_UPDATE) { 1430 dc->dc_state &= ~HPCFB_DC_UPDATE; 1431 hpcfb_redraw(cookie, dc->dc_min_row, 1432 dc->dc_max_row - dc->dc_min_row, 0); 1433 dc->dc_max_row = 0; 1434 dc->dc_min_row = dc->dc_rows; 1435 if (dc->dc_curx > 0 && dc->dc_cury > 0) 1436 hpcfb_cursor(dc, 1, dc->dc_cury, dc->dc_curx); 1437 return; 1438 } 1439 #endif /* HPCFB_JUMP */ 1440 hpcfb_redraw(cookie, dst, num, 0); 1441 } 1442 #ifdef HPCFB_JUMP 1443 hpcfb_check_update(dc); 1444 #endif /* HPCFB_JUMP */ 1445 } 1446 1447 /* 1448 * eraserows 1449 */ 1450 void 1451 hpcfb_tv_eraserows(struct hpcfb_devconfig *dc, 1452 int row, int nrow, long attr) 1453 { 1454 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1455 int cols; 1456 int i; 1457 1458 if (vscn == 0) 1459 return; 1460 1461 dc->dc_state |= HPCFB_DC_TDRAWING; 1462 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1463 #ifdef HPCFB_JUMP 1464 if (row < dc->dc_min_row) 1465 dc->dc_min_row = row; 1466 if (row + nrow > dc->dc_max_row) 1467 dc->dc_max_row = row + nrow; 1468 #endif /* HPCFB_JUMP */ 1469 1470 for (i = 0; i < nrow; i++) { 1471 cols = vscn[row+i].maxcol; 1472 if (vscn[row+i].spacecol < cols) 1473 vscn[row+i].spacecol = cols; 1474 vscn[row+i].maxcol = -1; 1475 } 1476 #ifdef HPCFB_JUMP 1477 hpcfb_check_update(dc); 1478 #endif /* HPCFB_JUMP */ 1479 } 1480 1481 void 1482 hpcfb_eraserows(void *cookie, int row, int nrow, long attr) 1483 { 1484 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1485 struct hpcfb_softc *sc = dc->dc_sc; 1486 struct rasops_info *ri = &dc->dc_rinfo; 1487 int yoff; 1488 int width; 1489 int height; 1490 1491 hpcfb_tv_eraserows(dc, row, nrow, attr); 1492 #ifdef HPCFB_JUMP 1493 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1494 dc->dc_state |= HPCFB_DC_UPDATE; 1495 return; 1496 } 1497 #endif /* HPCFB_JUMP */ 1498 if (!IS_DRAWABLE(dc)) { 1499 return; 1500 } 1501 1502 if (ri->ri_bits == NULL) 1503 return; 1504 1505 dc->dc_state |= HPCFB_DC_DRAWING; 1506 if (sc && sc->sc_accessops->erase 1507 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1508 yoff = row * ri->ri_font->fontheight; 1509 width = dc->dc_cols * ri->ri_font->fontwidth; 1510 height = nrow * ri->ri_font->fontheight; 1511 (*sc->sc_accessops->erase)(sc->sc_accessctx, 1512 0, yoff, height, width, attr); 1513 } else 1514 rasops_emul.eraserows(ri, row, nrow, attr); 1515 dc->dc_state &= ~HPCFB_DC_DRAWING; 1516 #ifdef HPCFB_JUMP 1517 hpcfb_check_update(dc); 1518 #endif /* HPCFB_JUMP */ 1519 } 1520 1521 /* 1522 * allocattr 1523 */ 1524 int 1525 hpcfb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp) 1526 { 1527 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1528 struct rasops_info *ri = &dc->dc_rinfo; 1529 1530 return (rasops_emul.allocattr(ri, fg, bg, flags, attrp)); 1531 } 1532