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