1 /* $NetBSD: hpcfb.c,v 1.50 2009/04/05 02:14:41 uwe 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.50 2009/04/05 02:14:41 uwe 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/user.h> 59 #include <sys/device.h> 60 #include <sys/conf.h> 61 #include <sys/malloc.h> 62 #include <sys/buf.h> 63 #include <sys/ioctl.h> 64 65 #include <uvm/uvm_extern.h> 66 67 #include <sys/bus.h> 68 69 #include <dev/wscons/wsconsio.h> 70 #include <dev/wscons/wsdisplayvar.h> 71 #include <dev/wscons/wscons_callbacks.h> 72 73 #include <dev/wsfont/wsfont.h> 74 #include <dev/rasops/rasops.h> 75 76 #include <dev/hpc/hpcfbvar.h> 77 #include <dev/hpc/hpcfbio.h> 78 79 #include "bivideo.h" 80 #if NBIVIDEO > 0 81 #include <dev/hpc/bivideovar.h> 82 #endif 83 84 #ifdef FBDEBUG 85 int hpcfb_debug = 0; 86 #define DPRINTF(arg) if (hpcfb_debug) printf arg 87 #else 88 #define DPRINTF(arg) do {} while (/* CONSTCOND */ 0) 89 #endif 90 91 #ifndef HPCFB_MAX_COLUMN 92 #define HPCFB_MAX_COLUMN 130 93 #endif /* HPCFB_MAX_COLUMN */ 94 #ifndef HPCFB_MAX_ROW 95 #define HPCFB_MAX_ROW 80 96 #endif /* HPCFB_MAX_ROW */ 97 98 /* 99 * currently experimental 100 #define HPCFB_JUMP 101 */ 102 103 struct hpcfb_vchar { 104 u_int c; 105 long attr; 106 }; 107 108 struct hpcfb_tvrow { 109 int maxcol; 110 int spacecol; 111 struct hpcfb_vchar col[HPCFB_MAX_COLUMN]; 112 }; 113 114 struct hpcfb_devconfig { 115 struct rasops_info dc_rinfo; /* rasops information */ 116 117 int dc_blanked; /* currently had video disabled */ 118 struct hpcfb_softc *dc_sc; 119 int dc_rows; 120 int dc_cols; 121 struct hpcfb_tvrow *dc_tvram; 122 int dc_curx; 123 int dc_cury; 124 #ifdef HPCFB_JUMP 125 int dc_min_row; 126 int dc_max_row; 127 int dc_scroll; 128 struct callout dc_scroll_ch; 129 int dc_scroll_src; 130 int dc_scroll_dst; 131 int dc_scroll_num; 132 #endif /* HPCFB_JUMP */ 133 volatile int dc_state; 134 #define HPCFB_DC_CURRENT 0x80000000 135 #define HPCFB_DC_DRAWING 0x01 /* drawing raster ops */ 136 #define HPCFB_DC_TDRAWING 0x02 /* drawing tvram */ 137 #define HPCFB_DC_SCROLLPENDING 0x04 /* scroll is pending */ 138 #define HPCFB_DC_UPDATE 0x08 /* tvram update */ 139 #define HPCFB_DC_SCRDELAY 0x10 /* scroll time but delay it */ 140 #define HPCFB_DC_SCRTHREAD 0x20 /* in scroll thread or callout */ 141 #define HPCFB_DC_UPDATEALL 0x40 /* need to redraw all */ 142 #define HPCFB_DC_ABORT 0x80 /* abort redrawing */ 143 #define HPCFB_DC_SWITCHREQ 0x100 /* switch request exist */ 144 int dc_memsize; 145 u_char *dc_fbaddr; 146 }; 147 148 #define IS_DRAWABLE(dc) \ 149 (((dc)->dc_state&HPCFB_DC_CURRENT)&& \ 150 (((dc)->dc_state&(HPCFB_DC_DRAWING|HPCFB_DC_SWITCHREQ)) == 0)) 151 152 #define HPCFB_MAX_SCREEN 5 153 #define HPCFB_MAX_JUMP 5 154 155 struct hpcfb_softc { 156 device_t sc_dev; 157 struct hpcfb_devconfig *sc_dc; /* device configuration */ 158 const struct hpcfb_accessops *sc_accessops; 159 void *sc_accessctx; 160 void *sc_powerhook; /* power management hook */ 161 device_t sc_wsdisplay; 162 int sc_screen_resumed; 163 int sc_polling; 164 int sc_mapping; 165 struct proc *sc_thread; 166 void *sc_wantedscreen; 167 void (*sc_switchcb)(void *, int, int); 168 void *sc_switchcbarg; 169 struct callout sc_switch_callout; 170 int sc_nfbconf; 171 struct hpcfb_fbconf *sc_fbconflist; 172 }; 173 174 /* 175 * function prototypes 176 */ 177 int hpcfbmatch(device_t, cfdata_t, void *); 178 void hpcfbattach(device_t, device_t, void *); 179 int hpcfbprint(void *, const char *); 180 181 int hpcfb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 182 paddr_t hpcfb_mmap(void *, void *, off_t, int); 183 184 void hpcfb_refresh_screen(struct hpcfb_softc *); 185 void hpcfb_doswitch(struct hpcfb_softc *); 186 187 #ifdef HPCFB_JUMP 188 static void hpcfb_thread(void *); 189 #endif /* HPCFB_JUMP */ 190 191 static int hpcfb_init(struct hpcfb_fbconf *, struct hpcfb_devconfig *); 192 static int hpcfb_alloc_screen(void *, const struct wsscreen_descr *, 193 void **, int *, int *, long *); 194 static void hpcfb_free_screen(void *, void *); 195 static int hpcfb_show_screen(void *, void *, int, 196 void (*) (void *, int, int), void *); 197 static void hpcfb_pollc(void *, int); 198 static void hpcfb_cmap_reorder(struct hpcfb_fbconf *, 199 struct hpcfb_devconfig *); 200 201 static void hpcfb_power(int, void *); 202 static bool hpcfb_suspend(device_t PMF_FN_PROTO); 203 static bool hpcfb_resume(device_t PMF_FN_PROTO); 204 205 206 void hpcfb_cursor(void *, int, int, int); 207 int hpcfb_mapchar(void *, int, unsigned int *); 208 void hpcfb_putchar(void *, int, int, u_int, long); 209 void hpcfb_copycols(void *, int, int, int, int); 210 void hpcfb_erasecols(void *, int, int, int, long); 211 void hpcfb_redraw(void *, int, int, int); 212 void hpcfb_copyrows(void *, int, int, int); 213 void hpcfb_eraserows(void *, int, int, long); 214 int hpcfb_allocattr(void *, int, int, int, long *); 215 void hpcfb_cursor_raw(void *, int, int, int); 216 217 #ifdef HPCFB_JUMP 218 void hpcfb_update(void *); 219 void hpcfb_do_scroll(void *); 220 void hpcfb_check_update(void *); 221 #endif /* HPCFB_JUMP */ 222 223 struct wsdisplay_emulops hpcfb_emulops = { 224 .cursor = hpcfb_cursor, 225 .mapchar = hpcfb_mapchar, 226 .putchar = hpcfb_putchar, 227 .copycols = hpcfb_copycols, 228 .erasecols = hpcfb_erasecols, 229 .copyrows = hpcfb_copyrows, 230 .eraserows = hpcfb_eraserows, 231 .allocattr = hpcfb_allocattr, 232 .replaceattr = NULL, 233 }; 234 235 /* 236 * static variables 237 */ 238 CFATTACH_DECL_NEW(hpcfb, sizeof(struct hpcfb_softc), 239 hpcfbmatch, hpcfbattach, NULL, NULL); 240 241 struct wsscreen_descr hpcfb_stdscreen = { 242 .name = "std", 243 .textops = &hpcfb_emulops, /* XXX */ 244 .capabilities = WSSCREEN_REVERSE, 245 /* XXX: ncols/nrows will be filled in -- shouldn't, they are global */ 246 }; 247 248 const struct wsscreen_descr *_hpcfb_scrlist[] = { 249 &hpcfb_stdscreen, 250 /* XXX other formats, graphics screen? */ 251 }; 252 253 struct wsscreen_list hpcfb_screenlist = { 254 .nscreens = __arraycount(_hpcfb_scrlist), 255 .screens = _hpcfb_scrlist, 256 }; 257 258 struct wsdisplay_accessops hpcfb_accessops = { 259 .ioctl = hpcfb_ioctl, 260 .mmap = hpcfb_mmap, 261 .alloc_screen = hpcfb_alloc_screen, 262 .free_screen = hpcfb_free_screen, 263 .show_screen = hpcfb_show_screen, 264 .load_font = NULL, 265 .pollc = hpcfb_pollc, 266 .scroll = NULL, 267 }; 268 269 void hpcfb_tv_putchar(struct hpcfb_devconfig *, int, int, u_int, long); 270 void hpcfb_tv_copycols(struct hpcfb_devconfig *, int, int, int, int); 271 void hpcfb_tv_erasecols(struct hpcfb_devconfig *, int, int, int, long); 272 void hpcfb_tv_copyrows(struct hpcfb_devconfig *, int, int, int); 273 void hpcfb_tv_eraserows(struct hpcfb_devconfig *, int, int, long); 274 275 struct wsdisplay_emulops rasops_emul; 276 277 static int hpcfbconsole; 278 struct hpcfb_devconfig hpcfb_console_dc; 279 struct wsscreen_descr hpcfb_console_wsscreen; 280 struct hpcfb_tvrow hpcfb_console_tvram[HPCFB_MAX_ROW]; 281 282 /* 283 * function bodies 284 */ 285 286 int 287 hpcfbmatch(device_t parent, cfdata_t match, void *aux) 288 { 289 return (1); 290 } 291 292 void 293 hpcfbattach(device_t parent, device_t self, void *aux) 294 { 295 struct hpcfb_softc *sc; 296 struct hpcfb_attach_args *ha = aux; 297 struct wsemuldisplaydev_attach_args wa; 298 299 sc = device_private(self); 300 sc->sc_dev = self; 301 302 sc->sc_accessops = ha->ha_accessops; 303 sc->sc_accessctx = ha->ha_accessctx; 304 sc->sc_nfbconf = ha->ha_nfbconf; 305 sc->sc_fbconflist = ha->ha_fbconflist; 306 307 if (hpcfbconsole) { 308 sc->sc_dc = &hpcfb_console_dc; 309 hpcfb_console_dc.dc_sc = sc; 310 printf(": %dx%d pixels, %d colors, %dx%d chars", 311 sc->sc_dc->dc_rinfo.ri_width,sc->sc_dc->dc_rinfo.ri_height, 312 (1 << sc->sc_dc->dc_rinfo.ri_depth), 313 sc->sc_dc->dc_rinfo.ri_cols,sc->sc_dc->dc_rinfo.ri_rows); 314 /* Set video chip dependent CLUT if any. */ 315 if (sc->sc_accessops->setclut) 316 sc->sc_accessops->setclut(sc->sc_accessctx, 317 &hpcfb_console_dc.dc_rinfo); 318 } 319 printf("\n"); 320 321 sc->sc_polling = 0; /* XXX */ 322 sc->sc_mapping = 0; /* XXX */ 323 callout_init(&sc->sc_switch_callout, 0); 324 325 wa.console = hpcfbconsole; 326 wa.scrdata = &hpcfb_screenlist; 327 wa.accessops = &hpcfb_accessops; 328 wa.accesscookie = sc; 329 330 sc->sc_wsdisplay = config_found(self, &wa, wsemuldisplaydevprint); 331 332 #ifdef HPCFB_JUMP 333 /* 334 * Create a kernel thread to scroll, 335 */ 336 if (kthread_create(PRI_NONE, 0, NULL, hpcfb_thread, sc, 337 &sc->sc_thread, "%s", device_xname(sc->sc_dev)) != 0) { 338 /* 339 * We were unable to create the HPCFB thread; bail out. 340 */ 341 sc->sc_thread = 0; 342 aprint_error_dev(sc->sc_dev, "unable to create thread, kernel " 343 "hpcfb scroll support disabled\n"); 344 } 345 #endif /* HPCFB_JUMP */ 346 347 /* 348 * apmdev(4) uses dopowerhooks(9), apm(4) uses pmf(9), and the 349 * two apm drivers are mutually exclusive. Register power 350 * hooks with both. 351 */ 352 sc->sc_powerhook = powerhook_establish(device_xname(sc->sc_dev), 353 hpcfb_power, sc); 354 if (sc->sc_powerhook == NULL) 355 aprint_error_dev(self, 356 "WARNING: unable to establish power hook\n"); 357 358 if (!pmf_device_register(self, hpcfb_suspend, hpcfb_resume)) 359 aprint_error_dev(self, "unable to establish power handler\n"); 360 } 361 362 #ifdef HPCFB_JUMP 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, 0); 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 struct wsdisplay_softc *wsc = device_private(sc->sc_wsdisplay); 652 653 sc->sc_screen_resumed = wsdisplay_getactivescreen(wsc); 654 655 if (wsdisplay_switch(sc->sc_wsdisplay, 656 WSDISPLAY_NULLSCREEN, 1 /* waitok */) == 0) { 657 wsscreen_switchwait(wsc, WSDISPLAY_NULLSCREEN); 658 } else { 659 sc->sc_screen_resumed = WSDISPLAY_NULLSCREEN; 660 } 661 662 sc->sc_dc->dc_state &= ~HPCFB_DC_CURRENT; 663 break; 664 } 665 case PWR_SOFTRESUME: 666 sc->sc_dc->dc_state |= HPCFB_DC_CURRENT; 667 if (sc->sc_screen_resumed != WSDISPLAY_NULLSCREEN) 668 wsdisplay_switch(sc->sc_wsdisplay, 669 sc->sc_screen_resumed, 1 /* waitok */); 670 break; 671 } 672 } 673 674 static bool 675 hpcfb_suspend(device_t self PMF_FN_ARGS) 676 { 677 struct hpcfb_softc *sc = device_private(self); 678 679 hpcfb_power(PWR_SOFTSUSPEND, sc); 680 return true; 681 } 682 683 static bool 684 hpcfb_resume(device_t self PMF_FN_ARGS) 685 { 686 struct hpcfb_softc *sc = device_private(self); 687 688 hpcfb_power(PWR_SOFTRESUME, sc); 689 return true; 690 } 691 692 void 693 hpcfb_refresh_screen(struct hpcfb_softc *sc) 694 { 695 struct hpcfb_devconfig *dc = sc->sc_dc; 696 int x, y; 697 698 DPRINTF(("hpcfb_refres_screen()\n")); 699 if (dc == NULL) 700 return; 701 702 #ifdef HPCFB_JUMP 703 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 704 dc->dc_state &= ~HPCFB_DC_SCROLLPENDING; 705 dc->dc_state &= ~HPCFB_DC_UPDATE; 706 callout_stop(&dc->dc_scroll_ch); 707 } 708 #endif /* HPCFB_JUMP */ 709 /* 710 * refresh screen 711 */ 712 dc->dc_state &= ~HPCFB_DC_UPDATEALL; 713 x = dc->dc_curx; 714 y = dc->dc_cury; 715 if (0 <= x && 0 <= y) 716 hpcfb_cursor_raw(dc, 0, y, x); /* disable cursor */ 717 /* redraw all text */ 718 hpcfb_redraw(dc, 0, dc->dc_rows, 1); 719 if (0 <= x && 0 <= y) 720 hpcfb_cursor_raw(dc, 1, y, x); /* enable cursor */ 721 } 722 723 static int 724 hpcfb_alloc_screen(void *v, const struct wsscreen_descr *type, 725 void **cookiep, int *curxp, int *curyp, long *attrp) 726 { 727 struct hpcfb_softc *sc = v; 728 struct hpcfb_devconfig *dc; 729 730 DPRINTF(("%s(%d): hpcfb_alloc_screen()\n", __FILE__, __LINE__)); 731 732 dc = malloc(sizeof(struct hpcfb_devconfig), M_DEVBUF, M_WAITOK|M_ZERO); 733 if (dc == NULL) 734 return (ENOMEM); 735 736 dc->dc_sc = sc; 737 if (hpcfb_init(&sc->sc_fbconflist[0], dc) != 0) 738 return (EINVAL); 739 if (sc->sc_accessops->font) { 740 sc->sc_accessops->font(sc->sc_accessctx, 741 dc->dc_rinfo.ri_font); 742 } 743 /* Set video chip dependent CLUT if any. */ 744 if (sc->sc_accessops->setclut) 745 sc->sc_accessops->setclut(sc->sc_accessctx, &dc->dc_rinfo); 746 printf("hpcfb: %dx%d pixels, %d colors, %dx%d chars\n", 747 dc->dc_rinfo.ri_width, dc->dc_rinfo.ri_height, 748 (1 << dc->dc_rinfo.ri_depth), 749 dc->dc_rinfo.ri_cols, dc->dc_rinfo.ri_rows); 750 751 /* 752 * XXX, wsdisplay won't reffer the information in wsscreen_descr 753 * structure until alloc_screen will be called, at least, under 754 * current implementation... 755 */ 756 hpcfb_stdscreen.nrows = dc->dc_rows; 757 hpcfb_stdscreen.ncols = dc->dc_cols; 758 hpcfb_stdscreen.capabilities = dc->dc_rinfo.ri_caps; 759 760 dc->dc_fbaddr = dc->dc_rinfo.ri_bits; 761 dc->dc_rows = dc->dc_rinfo.ri_rows; 762 dc->dc_cols = dc->dc_rinfo.ri_cols; 763 dc->dc_memsize = dc->dc_rinfo.ri_stride * dc->dc_rinfo.ri_height; 764 765 dc->dc_curx = -1; 766 dc->dc_cury = -1; 767 dc->dc_tvram = malloc(sizeof(struct hpcfb_tvrow)*dc->dc_rows, 768 M_DEVBUF, M_WAITOK|M_ZERO); 769 if (dc->dc_tvram == NULL){ 770 free(dc, M_DEVBUF); 771 return (ENOMEM); 772 } 773 774 *curxp = 0; 775 *curyp = 0; 776 *cookiep = dc; 777 hpcfb_allocattr(*cookiep, WSCOL_WHITE, WSCOL_BLACK, 0, attrp); 778 DPRINTF(("%s(%d): hpcfb_alloc_screen(): %p\n", 779 __FILE__, __LINE__, dc)); 780 781 return (0); 782 } 783 784 static void 785 hpcfb_free_screen(void *v, void *cookie) 786 { 787 struct hpcfb_devconfig *dc = cookie; 788 789 DPRINTF(("%s(%d): hpcfb_free_screen(%p)\n", 790 __FILE__, __LINE__, cookie)); 791 #ifdef DIAGNOSTIC 792 if (dc == &hpcfb_console_dc) 793 panic("hpcfb_free_screen: console"); 794 #endif 795 free(dc->dc_tvram, M_DEVBUF); 796 free(dc, M_DEVBUF); 797 } 798 799 static int 800 hpcfb_show_screen(void *v, void *cookie, int waitok, 801 void (*cb)(void *, int, int), void *cbarg) 802 { 803 struct hpcfb_softc *sc = v; 804 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 805 struct hpcfb_devconfig *odc; 806 807 DPRINTF(("%s(%d): hpcfb_show_screen(%p)\n", 808 __FILE__, __LINE__, dc)); 809 810 odc = sc->sc_dc; 811 812 if (dc == NULL || odc == dc) { 813 hpcfb_refresh_screen(sc); 814 return (0); 815 } 816 817 if (odc != NULL) { 818 odc->dc_state |= HPCFB_DC_SWITCHREQ; 819 820 if ((odc->dc_state&HPCFB_DC_DRAWING) != 0) { 821 odc->dc_state |= HPCFB_DC_ABORT; 822 } 823 } 824 825 sc->sc_wantedscreen = cookie; 826 sc->sc_switchcb = cb; 827 sc->sc_switchcbarg = cbarg; 828 if (cb) { 829 callout_reset(&sc->sc_switch_callout, 0, 830 (void(*)(void *))hpcfb_doswitch, sc); 831 return (EAGAIN); 832 } 833 834 hpcfb_doswitch(sc); 835 return (0); 836 } 837 838 void 839 hpcfb_doswitch(struct hpcfb_softc *sc) 840 { 841 struct hpcfb_devconfig *dc; 842 struct hpcfb_devconfig *odc; 843 844 DPRINTF(("hpcfb_doswitch()\n")); 845 odc = sc->sc_dc; 846 dc = sc->sc_wantedscreen; 847 848 if (!dc) { 849 (*sc->sc_switchcb)(sc->sc_switchcbarg, EIO, 0); 850 odc->dc_state &= ~HPCFB_DC_SWITCHREQ; 851 return; 852 } 853 854 if (odc == dc) { 855 odc->dc_state &= ~HPCFB_DC_SWITCHREQ; 856 return; 857 } 858 859 if (odc) { 860 #ifdef HPCFB_JUMP 861 odc->dc_state |= HPCFB_DC_ABORT; 862 #endif /* HPCFB_JUMP */ 863 864 if (odc->dc_curx >= 0 && odc->dc_cury >= 0) 865 hpcfb_cursor_raw(odc, 0, odc->dc_cury, odc->dc_curx); 866 /* disable cursor */ 867 /* disable old screen */ 868 odc->dc_state &= ~HPCFB_DC_CURRENT; 869 /* XXX, This is too dangerous. 870 odc->dc_rinfo.ri_bits = NULL; 871 */ 872 } 873 /* switch screen to new one */ 874 dc->dc_state |= HPCFB_DC_CURRENT; 875 dc->dc_state &= ~HPCFB_DC_ABORT; 876 dc->dc_rinfo.ri_bits = dc->dc_fbaddr; 877 sc->sc_dc = dc; 878 879 /* redraw screen image */ 880 hpcfb_refresh_screen(sc); 881 882 sc->sc_wantedscreen = NULL; 883 if (sc->sc_switchcb) 884 (*sc->sc_switchcb)(sc->sc_switchcbarg, 0, 0); 885 886 if (odc != NULL) 887 odc->dc_state &= ~HPCFB_DC_SWITCHREQ; 888 dc->dc_state &= ~HPCFB_DC_SWITCHREQ; 889 return; 890 } 891 892 static void 893 hpcfb_pollc(void *v, int on) 894 { 895 struct hpcfb_softc *sc = v; 896 897 if (sc == NULL) 898 return; 899 sc->sc_polling = on; 900 if (sc->sc_accessops->iodone) 901 (*sc->sc_accessops->iodone)(sc->sc_accessctx); 902 if (on) { 903 hpcfb_refresh_screen(sc); 904 if (sc->sc_accessops->iodone) 905 (*sc->sc_accessops->iodone)(sc->sc_accessctx); 906 } 907 908 return; 909 } 910 911 /* 912 * cursor 913 */ 914 void 915 hpcfb_cursor(void *cookie, int on, int row, int col) 916 { 917 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 918 919 if (on) { 920 dc->dc_curx = col; 921 dc->dc_cury = row; 922 } else { 923 dc->dc_curx = -1; 924 dc->dc_cury = -1; 925 } 926 927 hpcfb_cursor_raw(cookie, on, row, col); 928 } 929 930 void 931 hpcfb_cursor_raw(void *cookie, int on, int row, int col) 932 { 933 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 934 struct hpcfb_softc *sc = dc->dc_sc; 935 struct rasops_info *ri = &dc->dc_rinfo; 936 int curwidth, curheight; 937 int xoff, yoff; 938 939 #ifdef HPCFB_JUMP 940 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 941 dc->dc_state |= HPCFB_DC_UPDATE; 942 return; 943 } 944 #endif /* HPCFB_JUMP */ 945 if (!IS_DRAWABLE(dc)) { 946 return; 947 } 948 949 if (ri->ri_bits == NULL) 950 return; 951 952 dc->dc_state |= HPCFB_DC_DRAWING; 953 if (sc && sc->sc_accessops->cursor) { 954 xoff = col * ri->ri_font->fontwidth; 955 yoff = row * ri->ri_font->fontheight; 956 curheight = ri->ri_font->fontheight; 957 curwidth = ri->ri_font->fontwidth; 958 (*sc->sc_accessops->cursor)(sc->sc_accessctx, 959 on, xoff, yoff, curwidth, curheight); 960 } else 961 rasops_emul.cursor(ri, on, row, col); 962 dc->dc_state &= ~HPCFB_DC_DRAWING; 963 } 964 965 /* 966 * mapchar 967 */ 968 int 969 hpcfb_mapchar(void *cookie, int c, unsigned int *cp) 970 { 971 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 972 struct rasops_info *ri = &dc->dc_rinfo; 973 974 return (rasops_emul.mapchar(ri, c, cp)); 975 } 976 977 /* 978 * putchar 979 */ 980 void 981 hpcfb_tv_putchar(struct hpcfb_devconfig *dc, int row, int col, u_int uc, 982 long attr) 983 { 984 struct hpcfb_tvrow *vscn = dc->dc_tvram; 985 struct hpcfb_vchar *vc = &vscn[row].col[col]; 986 struct hpcfb_vchar *vcb; 987 988 if (vscn == 0) 989 return; 990 991 dc->dc_state |= HPCFB_DC_TDRAWING; 992 #ifdef HPCFB_JUMP 993 if (row < dc->dc_min_row) 994 dc->dc_min_row = row; 995 if (row > dc->dc_max_row) 996 dc->dc_max_row = row; 997 998 #endif /* HPCFB_JUMP */ 999 if (vscn[row].maxcol +1 == col) 1000 vscn[row].maxcol = col; 1001 else if (vscn[row].maxcol < col) { 1002 vcb = &vscn[row].col[vscn[row].maxcol+1]; 1003 memset(vcb, 0, 1004 sizeof(struct hpcfb_vchar)*(col-vscn[row].maxcol-1)); 1005 vscn[row].maxcol = col; 1006 } 1007 vc->c = uc; 1008 vc->attr = attr; 1009 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1010 #ifdef HPCFB_JUMP 1011 hpcfb_check_update(dc); 1012 #endif /* HPCFB_JUMP */ 1013 } 1014 1015 void 1016 hpcfb_putchar(void *cookie, int row, int col, u_int uc, long attr) 1017 { 1018 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1019 struct hpcfb_softc *sc = dc->dc_sc; 1020 struct rasops_info *ri = &dc->dc_rinfo; 1021 int xoff; 1022 int yoff; 1023 int fclr, uclr; 1024 struct wsdisplay_font *font; 1025 1026 hpcfb_tv_putchar(dc, row, col, uc, attr); 1027 #ifdef HPCFB_JUMP 1028 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1029 dc->dc_state |= HPCFB_DC_UPDATE; 1030 return; 1031 } 1032 #endif /* HPCFB_JUMP */ 1033 1034 if (!IS_DRAWABLE(dc)) { 1035 return; 1036 } 1037 1038 if (ri->ri_bits == NULL) 1039 return; 1040 1041 dc->dc_state |= HPCFB_DC_DRAWING; 1042 if (sc && sc->sc_accessops->putchar 1043 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1044 font = ri->ri_font; 1045 yoff = row * ri->ri_font->fontheight; 1046 xoff = col * ri->ri_font->fontwidth; 1047 fclr = ri->ri_devcmap[((u_int)attr >> 24) & 15]; 1048 uclr = ri->ri_devcmap[((u_int)attr >> 16) & 15]; 1049 1050 (*sc->sc_accessops->putchar)(sc->sc_accessctx, 1051 xoff, yoff, font, fclr, uclr, uc, attr); 1052 } else 1053 rasops_emul.putchar(ri, row, col, uc, attr); 1054 dc->dc_state &= ~HPCFB_DC_DRAWING; 1055 #ifdef HPCFB_JUMP 1056 hpcfb_check_update(dc); 1057 #endif /* HPCFB_JUMP */ 1058 } 1059 1060 /* 1061 * copycols 1062 */ 1063 void 1064 hpcfb_tv_copycols(struct hpcfb_devconfig *dc, int row, int srccol, int dstcol, 1065 int ncols) 1066 { 1067 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1068 struct hpcfb_vchar *svc = &vscn[row].col[srccol]; 1069 struct hpcfb_vchar *dvc = &vscn[row].col[dstcol]; 1070 1071 if (vscn == 0) 1072 return; 1073 1074 dc->dc_state |= HPCFB_DC_TDRAWING; 1075 #ifdef HPCFB_JUMP 1076 if (row < dc->dc_min_row) 1077 dc->dc_min_row = row; 1078 if (row > dc->dc_max_row) 1079 dc->dc_max_row = row; 1080 #endif /* HPCFB_JUMP */ 1081 1082 memcpy(dvc, svc, ncols*sizeof(struct hpcfb_vchar)); 1083 if (vscn[row].maxcol < srccol+ncols-1) 1084 vscn[row].maxcol = srccol+ncols-1; 1085 if (vscn[row].maxcol < dstcol+ncols-1) 1086 vscn[row].maxcol = dstcol+ncols-1; 1087 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1088 #ifdef HPCFB_JUMP 1089 hpcfb_check_update(dc); 1090 #endif /* HPCFB_JUMP */ 1091 } 1092 1093 void 1094 hpcfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1095 { 1096 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1097 struct hpcfb_softc *sc = dc->dc_sc; 1098 struct rasops_info *ri = &dc->dc_rinfo; 1099 int srcxoff,dstxoff; 1100 int srcyoff,dstyoff; 1101 int height, width; 1102 1103 hpcfb_tv_copycols(dc, row, srccol, dstcol, ncols); 1104 #ifdef HPCFB_JUMP 1105 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1106 dc->dc_state |= HPCFB_DC_UPDATE; 1107 return; 1108 } 1109 #endif /* HPCFB_JUMP */ 1110 if (!IS_DRAWABLE(dc)) { 1111 return; 1112 } 1113 1114 if (ri->ri_bits == NULL) 1115 return; 1116 1117 dc->dc_state |= HPCFB_DC_DRAWING; 1118 if (sc && sc->sc_accessops->bitblit 1119 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1120 srcxoff = srccol * ri->ri_font->fontwidth; 1121 srcyoff = row * ri->ri_font->fontheight; 1122 dstxoff = dstcol * ri->ri_font->fontwidth; 1123 dstyoff = row * ri->ri_font->fontheight; 1124 width = ncols * ri->ri_font->fontwidth; 1125 height = ri->ri_font->fontheight; 1126 (*sc->sc_accessops->bitblit)(sc->sc_accessctx, 1127 srcxoff, srcyoff, dstxoff, dstyoff, height, width); 1128 } else 1129 rasops_emul.copycols(ri, row, srccol, dstcol, ncols); 1130 dc->dc_state &= ~HPCFB_DC_DRAWING; 1131 #ifdef HPCFB_JUMP 1132 hpcfb_check_update(dc); 1133 #endif /* HPCFB_JUMP */ 1134 } 1135 1136 1137 /* 1138 * erasecols 1139 */ 1140 void 1141 hpcfb_tv_erasecols(struct hpcfb_devconfig *dc, 1142 int row, int startcol, int ncols, long attr) 1143 { 1144 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1145 1146 if (vscn == 0) 1147 return; 1148 1149 dc->dc_state |= HPCFB_DC_TDRAWING; 1150 #ifdef HPCFB_JUMP 1151 if (row < dc->dc_min_row) 1152 dc->dc_min_row = row; 1153 if (row > dc->dc_max_row) 1154 dc->dc_max_row = row; 1155 #endif /* HPCFB_JUMP */ 1156 1157 vscn[row].maxcol = startcol-1; 1158 if (vscn[row].spacecol < startcol+ncols-1) 1159 vscn[row].spacecol = startcol+ncols-1; 1160 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1161 #ifdef HPCFB_JUMP 1162 hpcfb_check_update(dc); 1163 #endif /* HPCFB_JUMP */ 1164 } 1165 1166 void 1167 hpcfb_erasecols(void *cookie, int row, int startcol, int ncols, long attr) 1168 { 1169 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1170 struct hpcfb_softc *sc = dc->dc_sc; 1171 struct rasops_info *ri = &dc->dc_rinfo; 1172 int xoff, yoff; 1173 int width, height; 1174 1175 hpcfb_tv_erasecols(dc, row, startcol, ncols, attr); 1176 #ifdef HPCFB_JUMP 1177 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1178 dc->dc_state |= HPCFB_DC_UPDATE; 1179 return; 1180 } 1181 #endif /* HPCFB_JUMP */ 1182 if (!IS_DRAWABLE(dc)) { 1183 return; 1184 } 1185 1186 if (ri->ri_bits == NULL) 1187 return; 1188 1189 dc->dc_state |= HPCFB_DC_DRAWING; 1190 if (sc && sc->sc_accessops->erase 1191 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1192 xoff = startcol * ri->ri_font->fontwidth; 1193 yoff = row * ri->ri_font->fontheight; 1194 width = ncols * ri->ri_font->fontwidth; 1195 height = ri->ri_font->fontheight; 1196 (*sc->sc_accessops->erase)(sc->sc_accessctx, 1197 xoff, yoff, height, width, attr); 1198 } else 1199 rasops_emul.erasecols(ri, row, startcol, ncols, attr); 1200 dc->dc_state &= ~HPCFB_DC_DRAWING; 1201 #ifdef HPCFB_JUMP 1202 hpcfb_check_update(dc); 1203 #endif /* HPCFB_JUMP */ 1204 } 1205 1206 /* 1207 * Copy rows. 1208 */ 1209 void 1210 hpcfb_tv_copyrows(struct hpcfb_devconfig *dc, int src, int dst, int num) 1211 { 1212 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1213 struct hpcfb_tvrow *svc = &vscn[src]; 1214 struct hpcfb_tvrow *dvc = &vscn[dst]; 1215 int i; 1216 int d; 1217 1218 if (vscn == 0) 1219 return; 1220 1221 dc->dc_state |= HPCFB_DC_TDRAWING; 1222 #ifdef HPCFB_JUMP 1223 if (dst < dc->dc_min_row) 1224 dc->dc_min_row = dst; 1225 if (dst + num > dc->dc_max_row) 1226 dc->dc_max_row = dst + num -1; 1227 #endif /* HPCFB_JUMP */ 1228 1229 if (svc > dvc) 1230 d = 1; 1231 else if (svc < dvc) { 1232 svc += num-1; 1233 dvc += num-1; 1234 d = -1; 1235 } else { 1236 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1237 #ifdef HPCFB_JUMP 1238 hpcfb_check_update(dc); 1239 #endif /* HPCFB_JUMP */ 1240 return; 1241 } 1242 1243 for (i = 0; i < num; i++) { 1244 memcpy(&dvc->col[0], &svc->col[0], sizeof(struct hpcfb_vchar)*(svc->maxcol+1)); 1245 if (svc->maxcol < dvc->maxcol && dvc->spacecol < dvc->maxcol) 1246 dvc->spacecol = dvc->maxcol; 1247 dvc->maxcol = svc->maxcol; 1248 svc+=d; 1249 dvc+=d; 1250 } 1251 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1252 #ifdef HPCFB_JUMP 1253 hpcfb_check_update(dc); 1254 #endif /* HPCFB_JUMP */ 1255 } 1256 1257 void 1258 hpcfb_redraw(void *cookie, int row, int num, int all) 1259 { 1260 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1261 struct rasops_info *ri = &dc->dc_rinfo; 1262 int cols; 1263 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1264 struct hpcfb_vchar *svc; 1265 int i, j; 1266 1267 #ifdef HPCFB_JUMP 1268 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1269 dc->dc_state |= HPCFB_DC_UPDATE; 1270 return; 1271 } 1272 #endif /* HPCFB_JUMP */ 1273 if (dc->dc_sc != NULL 1274 && !dc->dc_sc->sc_polling 1275 && dc->dc_sc->sc_mapping) 1276 return; 1277 1278 dc->dc_state &= ~HPCFB_DC_ABORT; 1279 1280 if (vscn == 0) 1281 return; 1282 1283 if (!IS_DRAWABLE(dc)) { 1284 return; 1285 } 1286 1287 if (ri->ri_bits == NULL) 1288 return; 1289 1290 dc->dc_state |= HPCFB_DC_DRAWING; 1291 dc->dc_state |= HPCFB_DC_TDRAWING; 1292 for (i = 0; i < num; i++) { 1293 if (dc->dc_state&HPCFB_DC_ABORT) 1294 break; 1295 if ((dc->dc_state&HPCFB_DC_CURRENT) == 0) 1296 break; 1297 cols = vscn[row+i].maxcol; 1298 for (j = 0; j <= cols; j++) { 1299 if (dc->dc_state&HPCFB_DC_ABORT) 1300 continue; 1301 if ((dc->dc_state&HPCFB_DC_CURRENT) == 0) 1302 continue; 1303 svc = &vscn[row+i].col[j]; 1304 rasops_emul.putchar(ri, row + i, j, svc->c, svc->attr); 1305 } 1306 if (all) 1307 cols = dc->dc_cols-1; 1308 else 1309 cols = vscn[row+i].spacecol; 1310 for (; j <= cols; j++) { 1311 if (dc->dc_state&HPCFB_DC_ABORT) 1312 continue; 1313 if ((dc->dc_state&HPCFB_DC_CURRENT) == 0) 1314 continue; 1315 rasops_emul.putchar(ri, row + i, j, ' ', 0); 1316 } 1317 vscn[row+i].spacecol = 0; 1318 } 1319 if (dc->dc_state&HPCFB_DC_ABORT) 1320 dc->dc_state &= ~HPCFB_DC_ABORT; 1321 dc->dc_state &= ~HPCFB_DC_DRAWING; 1322 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1323 #ifdef HPCFB_JUMP 1324 hpcfb_check_update(dc); 1325 #endif /* HPCFB_JUMP */ 1326 } 1327 1328 #ifdef HPCFB_JUMP 1329 void 1330 hpcfb_update(void *v) 1331 { 1332 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v; 1333 1334 /* callout_stop(&dc->dc_scroll_ch); */ 1335 dc->dc_state &= ~HPCFB_DC_SCROLLPENDING; 1336 if (dc->dc_curx > 0 && dc->dc_cury > 0) 1337 hpcfb_cursor_raw(dc, 0, dc->dc_cury, dc->dc_curx); 1338 if ((dc->dc_state&HPCFB_DC_UPDATEALL)) { 1339 hpcfb_redraw(dc, 0, dc->dc_rows, 1); 1340 dc->dc_state &= ~(HPCFB_DC_UPDATE|HPCFB_DC_UPDATEALL); 1341 } else if ((dc->dc_state&HPCFB_DC_UPDATE)) { 1342 hpcfb_redraw(dc, dc->dc_min_row, 1343 dc->dc_max_row - dc->dc_min_row, 0); 1344 dc->dc_state &= ~HPCFB_DC_UPDATE; 1345 } else { 1346 hpcfb_redraw(dc, dc->dc_scroll_dst, dc->dc_scroll_num, 0); 1347 } 1348 if (dc->dc_curx > 0 && dc->dc_cury > 0) 1349 hpcfb_cursor_raw(dc, 1, dc->dc_cury, dc->dc_curx); 1350 } 1351 1352 void 1353 hpcfb_do_scroll(void *v) 1354 { 1355 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v; 1356 1357 dc->dc_state |= HPCFB_DC_SCRTHREAD; 1358 if (dc->dc_state&(HPCFB_DC_DRAWING|HPCFB_DC_TDRAWING)) 1359 dc->dc_state |= HPCFB_DC_SCRDELAY; 1360 else if (dc->dc_sc != NULL && dc->dc_sc->sc_thread) 1361 wakeup(dc->dc_sc); 1362 else if (dc->dc_sc != NULL && !dc->dc_sc->sc_mapping) { 1363 /* draw only EMUL mode */ 1364 hpcfb_update(v); 1365 } 1366 dc->dc_state &= ~HPCFB_DC_SCRTHREAD; 1367 } 1368 1369 void 1370 hpcfb_check_update(void *v) 1371 { 1372 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v; 1373 1374 if (dc->dc_sc != NULL 1375 && dc->dc_sc->sc_polling 1376 && (dc->dc_state&HPCFB_DC_SCROLLPENDING)){ 1377 callout_stop(&dc->dc_scroll_ch); 1378 dc->dc_state &= ~HPCFB_DC_SCRDELAY; 1379 hpcfb_update(v); 1380 } 1381 else if (dc->dc_state&HPCFB_DC_SCRDELAY){ 1382 dc->dc_state &= ~HPCFB_DC_SCRDELAY; 1383 hpcfb_update(v); 1384 } else if (dc->dc_state&HPCFB_DC_UPDATEALL){ 1385 dc->dc_state &= ~HPCFB_DC_UPDATEALL; 1386 hpcfb_update(v); 1387 } 1388 } 1389 #endif /* HPCFB_JUMP */ 1390 1391 void 1392 hpcfb_copyrows(void *cookie, int src, int dst, int num) 1393 { 1394 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1395 struct rasops_info *ri = &dc->dc_rinfo; 1396 struct hpcfb_softc *sc = dc->dc_sc; 1397 int srcyoff, dstyoff; 1398 int width, height; 1399 1400 hpcfb_tv_copyrows(cookie, src, dst, num); 1401 1402 if (!IS_DRAWABLE(dc)) { 1403 return; 1404 } 1405 1406 if (ri->ri_bits == NULL) 1407 return; 1408 1409 if (sc && sc->sc_accessops->bitblit 1410 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1411 dc->dc_state |= HPCFB_DC_DRAWING; 1412 srcyoff = src * ri->ri_font->fontheight; 1413 dstyoff = dst * ri->ri_font->fontheight; 1414 width = dc->dc_cols * ri->ri_font->fontwidth; 1415 height = num * ri->ri_font->fontheight; 1416 (*sc->sc_accessops->bitblit)(sc->sc_accessctx, 1417 0, srcyoff, 0, dstyoff, height, width); 1418 dc->dc_state &= ~HPCFB_DC_DRAWING; 1419 } 1420 else { 1421 #ifdef HPCFB_JUMP 1422 if (sc && sc->sc_polling) { 1423 hpcfb_check_update(dc); 1424 } else if ((dc->dc_state&HPCFB_DC_SCROLLPENDING) == 0) { 1425 dc->dc_state |= HPCFB_DC_SCROLLPENDING; 1426 dc->dc_scroll = 1; 1427 dc->dc_scroll_src = src; 1428 dc->dc_scroll_dst = dst; 1429 dc->dc_scroll_num = num; 1430 callout_reset(&dc->dc_scroll_ch, hz/100, &hpcfb_do_scroll, dc); 1431 return; 1432 } else if (dc->dc_scroll++ < dc->dc_rows/HPCFB_MAX_JUMP) { 1433 dc->dc_state |= HPCFB_DC_UPDATE; 1434 return; 1435 } else { 1436 dc->dc_state &= ~HPCFB_DC_SCROLLPENDING; 1437 callout_stop(&dc->dc_scroll_ch); 1438 } 1439 if (dc->dc_state&HPCFB_DC_UPDATE) { 1440 dc->dc_state &= ~HPCFB_DC_UPDATE; 1441 hpcfb_redraw(cookie, dc->dc_min_row, 1442 dc->dc_max_row - dc->dc_min_row, 0); 1443 dc->dc_max_row = 0; 1444 dc->dc_min_row = dc->dc_rows; 1445 if (dc->dc_curx > 0 && dc->dc_cury > 0) 1446 hpcfb_cursor(dc, 1, dc->dc_cury, dc->dc_curx); 1447 return; 1448 } 1449 #endif /* HPCFB_JUMP */ 1450 hpcfb_redraw(cookie, dst, num, 0); 1451 } 1452 #ifdef HPCFB_JUMP 1453 hpcfb_check_update(dc); 1454 #endif /* HPCFB_JUMP */ 1455 } 1456 1457 /* 1458 * eraserows 1459 */ 1460 void 1461 hpcfb_tv_eraserows(struct hpcfb_devconfig *dc, 1462 int row, int nrow, long attr) 1463 { 1464 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1465 int cols; 1466 int i; 1467 1468 if (vscn == 0) 1469 return; 1470 1471 dc->dc_state |= HPCFB_DC_TDRAWING; 1472 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1473 #ifdef HPCFB_JUMP 1474 if (row < dc->dc_min_row) 1475 dc->dc_min_row = row; 1476 if (row + nrow > dc->dc_max_row) 1477 dc->dc_max_row = row + nrow; 1478 #endif /* HPCFB_JUMP */ 1479 1480 for (i = 0; i < nrow; i++) { 1481 cols = vscn[row+i].maxcol; 1482 if (vscn[row+i].spacecol < cols) 1483 vscn[row+i].spacecol = cols; 1484 vscn[row+i].maxcol = -1; 1485 } 1486 #ifdef HPCFB_JUMP 1487 hpcfb_check_update(dc); 1488 #endif /* HPCFB_JUMP */ 1489 } 1490 1491 void 1492 hpcfb_eraserows(void *cookie, int row, int nrow, long attr) 1493 { 1494 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1495 struct hpcfb_softc *sc = dc->dc_sc; 1496 struct rasops_info *ri = &dc->dc_rinfo; 1497 int yoff; 1498 int width; 1499 int height; 1500 1501 hpcfb_tv_eraserows(dc, row, nrow, attr); 1502 #ifdef HPCFB_JUMP 1503 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1504 dc->dc_state |= HPCFB_DC_UPDATE; 1505 return; 1506 } 1507 #endif /* HPCFB_JUMP */ 1508 if (!IS_DRAWABLE(dc)) { 1509 return; 1510 } 1511 1512 if (ri->ri_bits == NULL) 1513 return; 1514 1515 dc->dc_state |= HPCFB_DC_DRAWING; 1516 if (sc && sc->sc_accessops->erase 1517 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1518 yoff = row * ri->ri_font->fontheight; 1519 width = dc->dc_cols * ri->ri_font->fontwidth; 1520 height = nrow * ri->ri_font->fontheight; 1521 (*sc->sc_accessops->erase)(sc->sc_accessctx, 1522 0, yoff, height, width, attr); 1523 } else 1524 rasops_emul.eraserows(ri, row, nrow, attr); 1525 dc->dc_state &= ~HPCFB_DC_DRAWING; 1526 #ifdef HPCFB_JUMP 1527 hpcfb_check_update(dc); 1528 #endif /* HPCFB_JUMP */ 1529 } 1530 1531 /* 1532 * allocattr 1533 */ 1534 int 1535 hpcfb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp) 1536 { 1537 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1538 struct rasops_info *ri = &dc->dc_rinfo; 1539 1540 return (rasops_emul.allocattr(ri, fg, bg, flags, attrp)); 1541 } 1542