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