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