1 /* $NetBSD: hpcfb.c,v 1.60 2015/04/07 01:24:32 ozaki-r 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.60 2015/04/07 01:24:32 ozaki-r 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 aprint_error_dev(dc->dc_sc->sc_dev, "rasops_init() failed!"); 476 return -1; 477 } 478 479 /* over write color map of rasops */ 480 hpcfb_cmap_reorder (fbconf, dc); 481 482 dc->dc_curx = -1; 483 dc->dc_cury = -1; 484 dc->dc_rows = dc->dc_rinfo.ri_rows; 485 dc->dc_cols = dc->dc_rinfo.ri_cols; 486 #ifdef HPCFB_JUMP 487 dc->dc_max_row = 0; 488 dc->dc_min_row = dc->dc_rows; 489 dc->dc_scroll = 0; 490 callout_init(&dc->dc_scroll_ch, 0); 491 #endif /* HPCFB_JUMP */ 492 dc->dc_memsize = ri->ri_stride * ri->ri_height; 493 /* hook rasops in hpcfb_ops */ 494 rasops_emul = ri->ri_ops; /* struct copy */ 495 ri->ri_ops = hpcfb_emulops; /* struct copy */ 496 497 return (0); 498 } 499 500 static void 501 hpcfb_cmap_reorder(struct hpcfb_fbconf *fbconf, struct hpcfb_devconfig *dc) 502 { 503 struct rasops_info *ri = &dc->dc_rinfo; 504 int reverse = fbconf->hf_access_flags & HPCFB_ACCESS_REVERSE; 505 int *cmap = ri->ri_devcmap; 506 int i, j, bg, fg, tmp; 507 508 /* 509 * Set forground and background so that the screen 510 * looks black on white. 511 * Normally, black = 00 and white = ff. 512 * HPCFB_ACCESS_REVERSE means black = ff and white = 00. 513 */ 514 switch (fbconf->hf_pixel_width) { 515 case 1: 516 /* FALLTHROUGH */ 517 case 2: 518 /* FALLTHROUGH */ 519 case 4: 520 if (reverse) { 521 bg = 0; 522 fg = ~0; 523 } else { 524 bg = ~0; 525 fg = 0; 526 } 527 /* for gray-scale LCD, hi-contrast color map */ 528 cmap[0] = bg; 529 for (i = 1; i < 16; i++) 530 cmap[i] = fg; 531 break; 532 case 8: 533 /* FALLTHROUGH */ 534 case 16: 535 if (reverse) { 536 for (i = 0, j = 15; i < 8; i++, j--) { 537 tmp = cmap[i]; 538 cmap[i] = cmap[j]; 539 cmap[j] = tmp; 540 } 541 } 542 break; 543 } 544 } 545 546 int 547 hpcfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 548 struct lwp *l) 549 { 550 struct hpcfb_softc *sc = v; 551 struct hpcfb_devconfig *dc = sc->sc_dc; 552 struct wsdisplay_fbinfo *wdf; 553 554 DPRINTF(("hpcfb_ioctl(cmd=0x%lx)\n", cmd)); 555 switch (cmd) { 556 case WSKBDIO_BELL: 557 return (0); 558 break; 559 560 case WSDISPLAYIO_GTYPE: 561 *(u_int *)data = WSDISPLAY_TYPE_HPCFB; 562 return (0); 563 564 case WSDISPLAYIO_GINFO: 565 wdf = (void *)data; 566 wdf->height = dc->dc_rinfo.ri_height; 567 wdf->width = dc->dc_rinfo.ri_width; 568 wdf->depth = dc->dc_rinfo.ri_depth; 569 wdf->cmsize = 256; /* XXXX */ 570 return (0); 571 572 case WSDISPLAYIO_LINEBYTES: 573 *(u_int *)data = dc->dc_rinfo.ri_stride; 574 return 0; 575 576 case WSDISPLAYIO_SMODE: 577 if (*(int *)data == WSDISPLAYIO_MODE_EMUL){ 578 if (sc->sc_mapping){ 579 sc->sc_mapping = 0; 580 if (dc->dc_state&HPCFB_DC_DRAWING) 581 dc->dc_state &= ~HPCFB_DC_ABORT; 582 #ifdef HPCFB_FORCE_REDRAW 583 hpcfb_refresh_screen(sc); 584 #else 585 dc->dc_state |= HPCFB_DC_UPDATEALL; 586 #endif 587 } 588 } else { 589 if (!sc->sc_mapping) { 590 sc->sc_mapping = 1; 591 dc->dc_state |= HPCFB_DC_ABORT; 592 } 593 sc->sc_mapping = 1; 594 } 595 if (sc && sc->sc_accessops->iodone) 596 (*sc->sc_accessops->iodone)(sc->sc_accessctx); 597 return (0); 598 599 case WSDISPLAYIO_GETCMAP: 600 case WSDISPLAYIO_PUTCMAP: 601 case WSDISPLAYIO_SVIDEO: 602 case WSDISPLAYIO_GVIDEO: 603 case WSDISPLAYIO_GETPARAM: 604 case WSDISPLAYIO_SETPARAM: 605 case HPCFBIO_GCONF: 606 case HPCFBIO_SCONF: 607 case HPCFBIO_GDSPCONF: 608 case HPCFBIO_SDSPCONF: 609 case HPCFBIO_GOP: 610 case HPCFBIO_SOP: 611 return ((*sc->sc_accessops->ioctl)(sc->sc_accessctx, 612 cmd, data, flag, l)); 613 614 default: 615 if (IOCGROUP(cmd) != 't') 616 DPRINTF(("%s(%d): hpcfb_ioctl(%lx, %lx) grp=%c num=%ld\n", 617 __FILE__, __LINE__, 618 cmd, (u_long)data, (char)IOCGROUP(cmd), cmd&0xff)); 619 break; 620 } 621 622 return (EPASSTHROUGH); /* Inappropriate ioctl for device */ 623 } 624 625 paddr_t 626 hpcfb_mmap(void *v, void *vs, off_t offset, int prot) 627 { 628 struct hpcfb_softc *sc = v; 629 630 return ((*sc->sc_accessops->mmap)(sc->sc_accessctx, offset, prot)); 631 } 632 633 static void 634 hpcfb_power(int why, void *arg) 635 { 636 struct hpcfb_softc *sc = arg; 637 638 if (sc->sc_dc == NULL) 639 return; /* You have no screen yet. */ 640 641 switch (why) { 642 case PWR_STANDBY: 643 break; 644 case PWR_SOFTSUSPEND: { 645 struct wsdisplay_softc *wsc = device_private(sc->sc_wsdisplay); 646 647 sc->sc_screen_resumed = wsdisplay_getactivescreen(wsc); 648 649 if (wsdisplay_switch(sc->sc_wsdisplay, 650 WSDISPLAY_NULLSCREEN, 1 /* waitok */) == 0) { 651 wsscreen_switchwait(wsc, WSDISPLAY_NULLSCREEN); 652 } else { 653 sc->sc_screen_resumed = WSDISPLAY_NULLSCREEN; 654 } 655 656 sc->sc_dc->dc_state &= ~HPCFB_DC_CURRENT; 657 break; 658 } 659 case PWR_SOFTRESUME: 660 sc->sc_dc->dc_state |= HPCFB_DC_CURRENT; 661 if (sc->sc_screen_resumed != WSDISPLAY_NULLSCREEN) 662 wsdisplay_switch(sc->sc_wsdisplay, 663 sc->sc_screen_resumed, 1 /* waitok */); 664 break; 665 } 666 } 667 668 static bool 669 hpcfb_suspend(device_t self, const pmf_qual_t *qual) 670 { 671 struct hpcfb_softc *sc = device_private(self); 672 673 hpcfb_power(PWR_SOFTSUSPEND, sc); 674 return true; 675 } 676 677 static bool 678 hpcfb_resume(device_t self, const pmf_qual_t *qual) 679 { 680 struct hpcfb_softc *sc = device_private(self); 681 682 hpcfb_power(PWR_SOFTRESUME, sc); 683 return true; 684 } 685 686 void 687 hpcfb_refresh_screen(struct hpcfb_softc *sc) 688 { 689 struct hpcfb_devconfig *dc = sc->sc_dc; 690 int x, y; 691 692 DPRINTF(("hpcfb_refres_screen()\n")); 693 if (dc == NULL) 694 return; 695 696 #ifdef HPCFB_JUMP 697 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 698 dc->dc_state &= ~HPCFB_DC_SCROLLPENDING; 699 dc->dc_state &= ~HPCFB_DC_UPDATE; 700 callout_stop(&dc->dc_scroll_ch); 701 } 702 #endif /* HPCFB_JUMP */ 703 /* 704 * refresh screen 705 */ 706 dc->dc_state &= ~HPCFB_DC_UPDATEALL; 707 x = dc->dc_curx; 708 y = dc->dc_cury; 709 if (0 <= x && 0 <= y) 710 hpcfb_cursor_raw(dc, 0, y, x); /* disable cursor */ 711 /* redraw all text */ 712 hpcfb_redraw(dc, 0, dc->dc_rows, 1); 713 if (0 <= x && 0 <= y) 714 hpcfb_cursor_raw(dc, 1, y, x); /* enable cursor */ 715 } 716 717 static int 718 hpcfb_alloc_screen(void *v, const struct wsscreen_descr *type, 719 void **cookiep, int *curxp, int *curyp, long *attrp) 720 { 721 struct hpcfb_softc *sc = v; 722 struct hpcfb_devconfig *dc; 723 724 DPRINTF(("%s(%d): hpcfb_alloc_screen()\n", __FILE__, __LINE__)); 725 726 dc = malloc(sizeof(*dc), M_DEVBUF, M_WAITOK|M_ZERO); 727 if (dc == NULL) 728 return ENOMEM; 729 730 dc->dc_sc = sc; 731 if (hpcfb_init(&sc->sc_fbconflist[0], dc) != 0) { 732 free(dc, M_DEVBUF); 733 return EINVAL; 734 } 735 if (sc->sc_accessops->font) { 736 sc->sc_accessops->font(sc->sc_accessctx, 737 dc->dc_rinfo.ri_font); 738 } 739 /* Set video chip dependent CLUT if any. */ 740 if (sc->sc_accessops->setclut) 741 sc->sc_accessops->setclut(sc->sc_accessctx, &dc->dc_rinfo); 742 printf("hpcfb: %dx%d pixels, %d colors, %dx%d chars\n", 743 dc->dc_rinfo.ri_width, dc->dc_rinfo.ri_height, 744 (1 << dc->dc_rinfo.ri_depth), 745 dc->dc_rinfo.ri_cols, dc->dc_rinfo.ri_rows); 746 747 /* 748 * XXX, wsdisplay won't reffer the information in wsscreen_descr 749 * structure until alloc_screen will be called, at least, under 750 * current implementation... 751 */ 752 hpcfb_stdscreen.nrows = dc->dc_rows; 753 hpcfb_stdscreen.ncols = dc->dc_cols; 754 hpcfb_stdscreen.capabilities = dc->dc_rinfo.ri_caps; 755 756 dc->dc_fbaddr = dc->dc_rinfo.ri_bits; 757 dc->dc_rows = dc->dc_rinfo.ri_rows; 758 dc->dc_cols = dc->dc_rinfo.ri_cols; 759 dc->dc_memsize = dc->dc_rinfo.ri_stride * dc->dc_rinfo.ri_height; 760 761 dc->dc_curx = -1; 762 dc->dc_cury = -1; 763 dc->dc_tvram = malloc(sizeof(struct hpcfb_tvrow)*dc->dc_rows, 764 M_DEVBUF, M_WAITOK|M_ZERO); 765 if (dc->dc_tvram == NULL){ 766 free(dc, M_DEVBUF); 767 return (ENOMEM); 768 } 769 770 *curxp = 0; 771 *curyp = 0; 772 *cookiep = dc; 773 hpcfb_allocattr(*cookiep, WSCOL_WHITE, WSCOL_BLACK, 0, attrp); 774 DPRINTF(("%s(%d): hpcfb_alloc_screen(): %p\n", 775 __FILE__, __LINE__, dc)); 776 777 return (0); 778 } 779 780 static void 781 hpcfb_free_screen(void *v, void *cookie) 782 { 783 struct hpcfb_devconfig *dc = cookie; 784 785 DPRINTF(("%s(%d): hpcfb_free_screen(%p)\n", 786 __FILE__, __LINE__, cookie)); 787 #ifdef DIAGNOSTIC 788 if (dc == &hpcfb_console_dc) 789 panic("hpcfb_free_screen: console"); 790 #endif 791 free(dc->dc_tvram, M_DEVBUF); 792 free(dc, M_DEVBUF); 793 } 794 795 static int 796 hpcfb_show_screen(void *v, void *cookie, int waitok, 797 void (*cb)(void *, int, int), void *cbarg) 798 { 799 struct hpcfb_softc *sc = v; 800 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 801 struct hpcfb_devconfig *odc; 802 803 DPRINTF(("%s(%d): hpcfb_show_screen(%p)\n", 804 __FILE__, __LINE__, dc)); 805 806 odc = sc->sc_dc; 807 808 if (dc == NULL || odc == dc) { 809 hpcfb_refresh_screen(sc); 810 return (0); 811 } 812 813 if (odc != NULL) { 814 odc->dc_state |= HPCFB_DC_SWITCHREQ; 815 816 if ((odc->dc_state&HPCFB_DC_DRAWING) != 0) { 817 odc->dc_state |= HPCFB_DC_ABORT; 818 } 819 } 820 821 sc->sc_wantedscreen = cookie; 822 sc->sc_switchcb = cb; 823 sc->sc_switchcbarg = cbarg; 824 if (cb) { 825 callout_reset(&sc->sc_switch_callout, 0, 826 (void(*)(void *))hpcfb_doswitch, sc); 827 return (EAGAIN); 828 } 829 830 hpcfb_doswitch(sc); 831 return (0); 832 } 833 834 void 835 hpcfb_doswitch(struct hpcfb_softc *sc) 836 { 837 struct hpcfb_devconfig *dc; 838 struct hpcfb_devconfig *odc; 839 840 DPRINTF(("hpcfb_doswitch()\n")); 841 odc = sc->sc_dc; 842 dc = sc->sc_wantedscreen; 843 844 if (!dc) { 845 (*sc->sc_switchcb)(sc->sc_switchcbarg, EIO, 0); 846 odc->dc_state &= ~HPCFB_DC_SWITCHREQ; 847 return; 848 } 849 850 if (odc == dc) { 851 odc->dc_state &= ~HPCFB_DC_SWITCHREQ; 852 return; 853 } 854 855 if (odc) { 856 #ifdef HPCFB_JUMP 857 odc->dc_state |= HPCFB_DC_ABORT; 858 #endif /* HPCFB_JUMP */ 859 860 if (odc->dc_curx >= 0 && odc->dc_cury >= 0) 861 hpcfb_cursor_raw(odc, 0, odc->dc_cury, odc->dc_curx); 862 /* disable cursor */ 863 /* disable old screen */ 864 odc->dc_state &= ~HPCFB_DC_CURRENT; 865 /* XXX, This is too dangerous. 866 odc->dc_rinfo.ri_bits = NULL; 867 */ 868 } 869 /* switch screen to new one */ 870 dc->dc_state |= HPCFB_DC_CURRENT; 871 dc->dc_state &= ~HPCFB_DC_ABORT; 872 dc->dc_rinfo.ri_bits = dc->dc_fbaddr; 873 sc->sc_dc = dc; 874 875 /* redraw screen image */ 876 hpcfb_refresh_screen(sc); 877 878 sc->sc_wantedscreen = NULL; 879 if (sc->sc_switchcb) 880 (*sc->sc_switchcb)(sc->sc_switchcbarg, 0, 0); 881 882 if (odc != NULL) 883 odc->dc_state &= ~HPCFB_DC_SWITCHREQ; 884 dc->dc_state &= ~HPCFB_DC_SWITCHREQ; 885 return; 886 } 887 888 static void 889 hpcfb_pollc(void *v, int on) 890 { 891 struct hpcfb_softc *sc = v; 892 893 if (sc == NULL) 894 return; 895 sc->sc_polling = on; 896 if (sc->sc_accessops->iodone) 897 (*sc->sc_accessops->iodone)(sc->sc_accessctx); 898 if (on) { 899 hpcfb_refresh_screen(sc); 900 if (sc->sc_accessops->iodone) 901 (*sc->sc_accessops->iodone)(sc->sc_accessctx); 902 } 903 904 return; 905 } 906 907 /* 908 * cursor 909 */ 910 void 911 hpcfb_cursor(void *cookie, int on, int row, int col) 912 { 913 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 914 915 if (on) { 916 dc->dc_curx = col; 917 dc->dc_cury = row; 918 } else { 919 dc->dc_curx = -1; 920 dc->dc_cury = -1; 921 } 922 923 hpcfb_cursor_raw(cookie, on, row, col); 924 } 925 926 void 927 hpcfb_cursor_raw(void *cookie, int on, int row, int col) 928 { 929 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 930 struct hpcfb_softc *sc = dc->dc_sc; 931 struct rasops_info *ri = &dc->dc_rinfo; 932 int curwidth, curheight; 933 int xoff, yoff; 934 935 #ifdef HPCFB_JUMP 936 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 937 dc->dc_state |= HPCFB_DC_UPDATE; 938 return; 939 } 940 #endif /* HPCFB_JUMP */ 941 if (!IS_DRAWABLE(dc)) { 942 return; 943 } 944 945 if (ri->ri_bits == NULL) 946 return; 947 948 dc->dc_state |= HPCFB_DC_DRAWING; 949 if (sc && sc->sc_accessops->cursor) { 950 xoff = col * ri->ri_font->fontwidth; 951 yoff = row * ri->ri_font->fontheight; 952 curheight = ri->ri_font->fontheight; 953 curwidth = ri->ri_font->fontwidth; 954 (*sc->sc_accessops->cursor)(sc->sc_accessctx, 955 on, xoff, yoff, curwidth, curheight); 956 } else 957 rasops_emul.cursor(ri, on, row, col); 958 dc->dc_state &= ~HPCFB_DC_DRAWING; 959 } 960 961 /* 962 * mapchar 963 */ 964 int 965 hpcfb_mapchar(void *cookie, int c, unsigned int *cp) 966 { 967 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 968 struct rasops_info *ri = &dc->dc_rinfo; 969 970 return (rasops_emul.mapchar(ri, c, cp)); 971 } 972 973 /* 974 * putchar 975 */ 976 void 977 hpcfb_tv_putchar(struct hpcfb_devconfig *dc, int row, int col, u_int uc, 978 long attr) 979 { 980 struct hpcfb_tvrow *vscn = dc->dc_tvram; 981 struct hpcfb_vchar *vc = &vscn[row].col[col]; 982 struct hpcfb_vchar *vcb; 983 984 if (vscn == 0) 985 return; 986 987 dc->dc_state |= HPCFB_DC_TDRAWING; 988 #ifdef HPCFB_JUMP 989 if (row < dc->dc_min_row) 990 dc->dc_min_row = row; 991 if (row > dc->dc_max_row) 992 dc->dc_max_row = row; 993 994 #endif /* HPCFB_JUMP */ 995 if (vscn[row].maxcol +1 == col) 996 vscn[row].maxcol = col; 997 else if (vscn[row].maxcol < col) { 998 vcb = &vscn[row].col[vscn[row].maxcol+1]; 999 memset(vcb, 0, 1000 sizeof(struct hpcfb_vchar)*(col-vscn[row].maxcol-1)); 1001 vscn[row].maxcol = col; 1002 } 1003 vc->c = uc; 1004 vc->attr = attr; 1005 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1006 #ifdef HPCFB_JUMP 1007 hpcfb_check_update(dc); 1008 #endif /* HPCFB_JUMP */ 1009 } 1010 1011 void 1012 hpcfb_putchar(void *cookie, int row, int col, u_int uc, long attr) 1013 { 1014 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1015 struct hpcfb_softc *sc = dc->dc_sc; 1016 struct rasops_info *ri = &dc->dc_rinfo; 1017 int xoff; 1018 int yoff; 1019 int fclr, uclr; 1020 struct wsdisplay_font *font; 1021 1022 hpcfb_tv_putchar(dc, row, col, uc, attr); 1023 #ifdef HPCFB_JUMP 1024 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1025 dc->dc_state |= HPCFB_DC_UPDATE; 1026 return; 1027 } 1028 #endif /* HPCFB_JUMP */ 1029 1030 if (!IS_DRAWABLE(dc)) { 1031 return; 1032 } 1033 1034 if (ri->ri_bits == NULL) 1035 return; 1036 1037 dc->dc_state |= HPCFB_DC_DRAWING; 1038 if (sc && sc->sc_accessops->putchar 1039 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1040 font = ri->ri_font; 1041 yoff = row * ri->ri_font->fontheight; 1042 xoff = col * ri->ri_font->fontwidth; 1043 fclr = ri->ri_devcmap[((u_int)attr >> 24) & 15]; 1044 uclr = ri->ri_devcmap[((u_int)attr >> 16) & 15]; 1045 1046 (*sc->sc_accessops->putchar)(sc->sc_accessctx, 1047 xoff, yoff, font, fclr, uclr, uc, attr); 1048 } else 1049 rasops_emul.putchar(ri, row, col, uc, attr); 1050 dc->dc_state &= ~HPCFB_DC_DRAWING; 1051 #ifdef HPCFB_JUMP 1052 hpcfb_check_update(dc); 1053 #endif /* HPCFB_JUMP */ 1054 } 1055 1056 /* 1057 * copycols 1058 */ 1059 void 1060 hpcfb_tv_copycols(struct hpcfb_devconfig *dc, int row, int srccol, int dstcol, 1061 int ncols) 1062 { 1063 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1064 struct hpcfb_vchar *svc = &vscn[row].col[srccol]; 1065 struct hpcfb_vchar *dvc = &vscn[row].col[dstcol]; 1066 1067 if (vscn == 0) 1068 return; 1069 1070 dc->dc_state |= HPCFB_DC_TDRAWING; 1071 #ifdef HPCFB_JUMP 1072 if (row < dc->dc_min_row) 1073 dc->dc_min_row = row; 1074 if (row > dc->dc_max_row) 1075 dc->dc_max_row = row; 1076 #endif /* HPCFB_JUMP */ 1077 1078 memcpy(dvc, svc, ncols*sizeof(struct hpcfb_vchar)); 1079 if (vscn[row].maxcol < srccol+ncols-1) 1080 vscn[row].maxcol = srccol+ncols-1; 1081 if (vscn[row].maxcol < dstcol+ncols-1) 1082 vscn[row].maxcol = dstcol+ncols-1; 1083 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1084 #ifdef HPCFB_JUMP 1085 hpcfb_check_update(dc); 1086 #endif /* HPCFB_JUMP */ 1087 } 1088 1089 void 1090 hpcfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1091 { 1092 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1093 struct hpcfb_softc *sc = dc->dc_sc; 1094 struct rasops_info *ri = &dc->dc_rinfo; 1095 int srcxoff,dstxoff; 1096 int srcyoff,dstyoff; 1097 int height, width; 1098 1099 hpcfb_tv_copycols(dc, row, srccol, dstcol, ncols); 1100 #ifdef HPCFB_JUMP 1101 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1102 dc->dc_state |= HPCFB_DC_UPDATE; 1103 return; 1104 } 1105 #endif /* HPCFB_JUMP */ 1106 if (!IS_DRAWABLE(dc)) { 1107 return; 1108 } 1109 1110 if (ri->ri_bits == NULL) 1111 return; 1112 1113 dc->dc_state |= HPCFB_DC_DRAWING; 1114 if (sc && sc->sc_accessops->bitblit 1115 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1116 srcxoff = srccol * ri->ri_font->fontwidth; 1117 srcyoff = row * ri->ri_font->fontheight; 1118 dstxoff = dstcol * ri->ri_font->fontwidth; 1119 dstyoff = row * ri->ri_font->fontheight; 1120 width = ncols * ri->ri_font->fontwidth; 1121 height = ri->ri_font->fontheight; 1122 (*sc->sc_accessops->bitblit)(sc->sc_accessctx, 1123 srcxoff, srcyoff, dstxoff, dstyoff, height, width); 1124 } else 1125 rasops_emul.copycols(ri, row, srccol, dstcol, ncols); 1126 dc->dc_state &= ~HPCFB_DC_DRAWING; 1127 #ifdef HPCFB_JUMP 1128 hpcfb_check_update(dc); 1129 #endif /* HPCFB_JUMP */ 1130 } 1131 1132 1133 /* 1134 * erasecols 1135 */ 1136 void 1137 hpcfb_tv_erasecols(struct hpcfb_devconfig *dc, 1138 int row, int startcol, int ncols, long attr) 1139 { 1140 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1141 1142 if (vscn == 0) 1143 return; 1144 1145 dc->dc_state |= HPCFB_DC_TDRAWING; 1146 #ifdef HPCFB_JUMP 1147 if (row < dc->dc_min_row) 1148 dc->dc_min_row = row; 1149 if (row > dc->dc_max_row) 1150 dc->dc_max_row = row; 1151 #endif /* HPCFB_JUMP */ 1152 1153 vscn[row].maxcol = startcol-1; 1154 if (vscn[row].spacecol < startcol+ncols-1) 1155 vscn[row].spacecol = startcol+ncols-1; 1156 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1157 #ifdef HPCFB_JUMP 1158 hpcfb_check_update(dc); 1159 #endif /* HPCFB_JUMP */ 1160 } 1161 1162 void 1163 hpcfb_erasecols(void *cookie, int row, int startcol, int ncols, long attr) 1164 { 1165 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1166 struct hpcfb_softc *sc = dc->dc_sc; 1167 struct rasops_info *ri = &dc->dc_rinfo; 1168 int xoff, yoff; 1169 int width, height; 1170 1171 hpcfb_tv_erasecols(dc, row, startcol, ncols, attr); 1172 #ifdef HPCFB_JUMP 1173 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1174 dc->dc_state |= HPCFB_DC_UPDATE; 1175 return; 1176 } 1177 #endif /* HPCFB_JUMP */ 1178 if (!IS_DRAWABLE(dc)) { 1179 return; 1180 } 1181 1182 if (ri->ri_bits == NULL) 1183 return; 1184 1185 dc->dc_state |= HPCFB_DC_DRAWING; 1186 if (sc && sc->sc_accessops->erase 1187 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1188 xoff = startcol * ri->ri_font->fontwidth; 1189 yoff = row * ri->ri_font->fontheight; 1190 width = ncols * ri->ri_font->fontwidth; 1191 height = ri->ri_font->fontheight; 1192 (*sc->sc_accessops->erase)(sc->sc_accessctx, 1193 xoff, yoff, height, width, attr); 1194 } else 1195 rasops_emul.erasecols(ri, row, startcol, ncols, attr); 1196 dc->dc_state &= ~HPCFB_DC_DRAWING; 1197 #ifdef HPCFB_JUMP 1198 hpcfb_check_update(dc); 1199 #endif /* HPCFB_JUMP */ 1200 } 1201 1202 /* 1203 * Copy rows. 1204 */ 1205 void 1206 hpcfb_tv_copyrows(struct hpcfb_devconfig *dc, int src, int dst, int num) 1207 { 1208 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1209 struct hpcfb_tvrow *svc = &vscn[src]; 1210 struct hpcfb_tvrow *dvc = &vscn[dst]; 1211 int i; 1212 int d; 1213 1214 if (vscn == 0) 1215 return; 1216 1217 dc->dc_state |= HPCFB_DC_TDRAWING; 1218 #ifdef HPCFB_JUMP 1219 if (dst < dc->dc_min_row) 1220 dc->dc_min_row = dst; 1221 if (dst + num > dc->dc_max_row) 1222 dc->dc_max_row = dst + num -1; 1223 #endif /* HPCFB_JUMP */ 1224 1225 if (svc > dvc) 1226 d = 1; 1227 else if (svc < dvc) { 1228 svc += num-1; 1229 dvc += num-1; 1230 d = -1; 1231 } else { 1232 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1233 #ifdef HPCFB_JUMP 1234 hpcfb_check_update(dc); 1235 #endif /* HPCFB_JUMP */ 1236 return; 1237 } 1238 1239 for (i = 0; i < num; i++) { 1240 memcpy(&dvc->col[0], &svc->col[0], sizeof(struct hpcfb_vchar)*(svc->maxcol+1)); 1241 if (svc->maxcol < dvc->maxcol && dvc->spacecol < dvc->maxcol) 1242 dvc->spacecol = dvc->maxcol; 1243 dvc->maxcol = svc->maxcol; 1244 svc+=d; 1245 dvc+=d; 1246 } 1247 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1248 #ifdef HPCFB_JUMP 1249 hpcfb_check_update(dc); 1250 #endif /* HPCFB_JUMP */ 1251 } 1252 1253 void 1254 hpcfb_redraw(void *cookie, int row, int num, int all) 1255 { 1256 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1257 struct rasops_info *ri = &dc->dc_rinfo; 1258 int cols; 1259 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1260 struct hpcfb_vchar *svc; 1261 int i, j; 1262 1263 #ifdef HPCFB_JUMP 1264 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1265 dc->dc_state |= HPCFB_DC_UPDATE; 1266 return; 1267 } 1268 #endif /* HPCFB_JUMP */ 1269 if (dc->dc_sc != NULL 1270 && !dc->dc_sc->sc_polling 1271 && dc->dc_sc->sc_mapping) 1272 return; 1273 1274 dc->dc_state &= ~HPCFB_DC_ABORT; 1275 1276 if (vscn == 0) 1277 return; 1278 1279 if (!IS_DRAWABLE(dc)) { 1280 return; 1281 } 1282 1283 if (ri->ri_bits == NULL) 1284 return; 1285 1286 dc->dc_state |= HPCFB_DC_DRAWING; 1287 dc->dc_state |= HPCFB_DC_TDRAWING; 1288 for (i = 0; i < num; i++) { 1289 if (dc->dc_state&HPCFB_DC_ABORT) 1290 break; 1291 if ((dc->dc_state&HPCFB_DC_CURRENT) == 0) 1292 break; 1293 cols = vscn[row+i].maxcol; 1294 for (j = 0; j <= cols; j++) { 1295 if (dc->dc_state&HPCFB_DC_ABORT) 1296 continue; 1297 if ((dc->dc_state&HPCFB_DC_CURRENT) == 0) 1298 continue; 1299 svc = &vscn[row+i].col[j]; 1300 rasops_emul.putchar(ri, row + i, j, svc->c, svc->attr); 1301 } 1302 if (all) 1303 cols = dc->dc_cols-1; 1304 else 1305 cols = vscn[row+i].spacecol; 1306 for (; j <= cols; j++) { 1307 if (dc->dc_state&HPCFB_DC_ABORT) 1308 continue; 1309 if ((dc->dc_state&HPCFB_DC_CURRENT) == 0) 1310 continue; 1311 rasops_emul.putchar(ri, row + i, j, ' ', 0); 1312 } 1313 vscn[row+i].spacecol = 0; 1314 } 1315 if (dc->dc_state&HPCFB_DC_ABORT) 1316 dc->dc_state &= ~HPCFB_DC_ABORT; 1317 dc->dc_state &= ~HPCFB_DC_DRAWING; 1318 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1319 #ifdef HPCFB_JUMP 1320 hpcfb_check_update(dc); 1321 #endif /* HPCFB_JUMP */ 1322 } 1323 1324 #ifdef HPCFB_JUMP 1325 void 1326 hpcfb_update(void *v) 1327 { 1328 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v; 1329 1330 /* callout_stop(&dc->dc_scroll_ch); */ 1331 dc->dc_state &= ~HPCFB_DC_SCROLLPENDING; 1332 if (dc->dc_curx > 0 && dc->dc_cury > 0) 1333 hpcfb_cursor_raw(dc, 0, dc->dc_cury, dc->dc_curx); 1334 if ((dc->dc_state&HPCFB_DC_UPDATEALL)) { 1335 hpcfb_redraw(dc, 0, dc->dc_rows, 1); 1336 dc->dc_state &= ~(HPCFB_DC_UPDATE|HPCFB_DC_UPDATEALL); 1337 } else if ((dc->dc_state&HPCFB_DC_UPDATE)) { 1338 hpcfb_redraw(dc, dc->dc_min_row, 1339 dc->dc_max_row - dc->dc_min_row, 0); 1340 dc->dc_state &= ~HPCFB_DC_UPDATE; 1341 } else { 1342 hpcfb_redraw(dc, dc->dc_scroll_dst, dc->dc_scroll_num, 0); 1343 } 1344 if (dc->dc_curx > 0 && dc->dc_cury > 0) 1345 hpcfb_cursor_raw(dc, 1, dc->dc_cury, dc->dc_curx); 1346 } 1347 1348 void 1349 hpcfb_do_scroll(void *v) 1350 { 1351 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v; 1352 1353 dc->dc_state |= HPCFB_DC_SCRTHREAD; 1354 if (dc->dc_state&(HPCFB_DC_DRAWING|HPCFB_DC_TDRAWING)) 1355 dc->dc_state |= HPCFB_DC_SCRDELAY; 1356 else if (dc->dc_sc != NULL && dc->dc_sc->sc_thread) 1357 wakeup(dc->dc_sc); 1358 else if (dc->dc_sc != NULL && !dc->dc_sc->sc_mapping) { 1359 /* draw only EMUL mode */ 1360 hpcfb_update(v); 1361 } 1362 dc->dc_state &= ~HPCFB_DC_SCRTHREAD; 1363 } 1364 1365 void 1366 hpcfb_check_update(void *v) 1367 { 1368 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)v; 1369 1370 if (dc->dc_sc != NULL 1371 && dc->dc_sc->sc_polling 1372 && (dc->dc_state&HPCFB_DC_SCROLLPENDING)){ 1373 callout_stop(&dc->dc_scroll_ch); 1374 dc->dc_state &= ~HPCFB_DC_SCRDELAY; 1375 hpcfb_update(v); 1376 } 1377 else if (dc->dc_state&HPCFB_DC_SCRDELAY){ 1378 dc->dc_state &= ~HPCFB_DC_SCRDELAY; 1379 hpcfb_update(v); 1380 } else if (dc->dc_state&HPCFB_DC_UPDATEALL){ 1381 dc->dc_state &= ~HPCFB_DC_UPDATEALL; 1382 hpcfb_update(v); 1383 } 1384 } 1385 #endif /* HPCFB_JUMP */ 1386 1387 void 1388 hpcfb_copyrows(void *cookie, int src, int dst, int num) 1389 { 1390 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1391 struct rasops_info *ri = &dc->dc_rinfo; 1392 struct hpcfb_softc *sc = dc->dc_sc; 1393 int srcyoff, dstyoff; 1394 int width, height; 1395 1396 hpcfb_tv_copyrows(cookie, src, dst, num); 1397 1398 if (!IS_DRAWABLE(dc)) { 1399 return; 1400 } 1401 1402 if (ri->ri_bits == NULL) 1403 return; 1404 1405 if (sc && sc->sc_accessops->bitblit 1406 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1407 dc->dc_state |= HPCFB_DC_DRAWING; 1408 srcyoff = src * ri->ri_font->fontheight; 1409 dstyoff = dst * ri->ri_font->fontheight; 1410 width = dc->dc_cols * ri->ri_font->fontwidth; 1411 height = num * ri->ri_font->fontheight; 1412 (*sc->sc_accessops->bitblit)(sc->sc_accessctx, 1413 0, srcyoff, 0, dstyoff, height, width); 1414 dc->dc_state &= ~HPCFB_DC_DRAWING; 1415 } 1416 else { 1417 #ifdef HPCFB_JUMP 1418 if (sc && sc->sc_polling) { 1419 hpcfb_check_update(dc); 1420 } else if ((dc->dc_state&HPCFB_DC_SCROLLPENDING) == 0) { 1421 dc->dc_state |= HPCFB_DC_SCROLLPENDING; 1422 dc->dc_scroll = 1; 1423 dc->dc_scroll_src = src; 1424 dc->dc_scroll_dst = dst; 1425 dc->dc_scroll_num = num; 1426 callout_reset(&dc->dc_scroll_ch, hz/100, &hpcfb_do_scroll, dc); 1427 return; 1428 } else if (dc->dc_scroll++ < dc->dc_rows/HPCFB_MAX_JUMP) { 1429 dc->dc_state |= HPCFB_DC_UPDATE; 1430 return; 1431 } else { 1432 dc->dc_state &= ~HPCFB_DC_SCROLLPENDING; 1433 callout_stop(&dc->dc_scroll_ch); 1434 } 1435 if (dc->dc_state&HPCFB_DC_UPDATE) { 1436 dc->dc_state &= ~HPCFB_DC_UPDATE; 1437 hpcfb_redraw(cookie, dc->dc_min_row, 1438 dc->dc_max_row - dc->dc_min_row, 0); 1439 dc->dc_max_row = 0; 1440 dc->dc_min_row = dc->dc_rows; 1441 if (dc->dc_curx > 0 && dc->dc_cury > 0) 1442 hpcfb_cursor(dc, 1, dc->dc_cury, dc->dc_curx); 1443 return; 1444 } 1445 #endif /* HPCFB_JUMP */ 1446 hpcfb_redraw(cookie, dst, num, 0); 1447 } 1448 #ifdef HPCFB_JUMP 1449 hpcfb_check_update(dc); 1450 #endif /* HPCFB_JUMP */ 1451 } 1452 1453 /* 1454 * eraserows 1455 */ 1456 void 1457 hpcfb_tv_eraserows(struct hpcfb_devconfig *dc, 1458 int row, int nrow, long attr) 1459 { 1460 struct hpcfb_tvrow *vscn = dc->dc_tvram; 1461 int cols; 1462 int i; 1463 1464 if (vscn == 0) 1465 return; 1466 1467 dc->dc_state |= HPCFB_DC_TDRAWING; 1468 dc->dc_state &= ~HPCFB_DC_TDRAWING; 1469 #ifdef HPCFB_JUMP 1470 if (row < dc->dc_min_row) 1471 dc->dc_min_row = row; 1472 if (row + nrow > dc->dc_max_row) 1473 dc->dc_max_row = row + nrow; 1474 #endif /* HPCFB_JUMP */ 1475 1476 for (i = 0; i < nrow; i++) { 1477 cols = vscn[row+i].maxcol; 1478 if (vscn[row+i].spacecol < cols) 1479 vscn[row+i].spacecol = cols; 1480 vscn[row+i].maxcol = -1; 1481 } 1482 #ifdef HPCFB_JUMP 1483 hpcfb_check_update(dc); 1484 #endif /* HPCFB_JUMP */ 1485 } 1486 1487 void 1488 hpcfb_eraserows(void *cookie, int row, int nrow, long attr) 1489 { 1490 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1491 struct hpcfb_softc *sc = dc->dc_sc; 1492 struct rasops_info *ri = &dc->dc_rinfo; 1493 int yoff; 1494 int width; 1495 int height; 1496 1497 hpcfb_tv_eraserows(dc, row, nrow, attr); 1498 #ifdef HPCFB_JUMP 1499 if (dc->dc_state&HPCFB_DC_SCROLLPENDING) { 1500 dc->dc_state |= HPCFB_DC_UPDATE; 1501 return; 1502 } 1503 #endif /* HPCFB_JUMP */ 1504 if (!IS_DRAWABLE(dc)) { 1505 return; 1506 } 1507 1508 if (ri->ri_bits == NULL) 1509 return; 1510 1511 dc->dc_state |= HPCFB_DC_DRAWING; 1512 if (sc && sc->sc_accessops->erase 1513 && (dc->dc_state&HPCFB_DC_CURRENT)) { 1514 yoff = row * ri->ri_font->fontheight; 1515 width = dc->dc_cols * ri->ri_font->fontwidth; 1516 height = nrow * ri->ri_font->fontheight; 1517 (*sc->sc_accessops->erase)(sc->sc_accessctx, 1518 0, yoff, height, width, attr); 1519 } else 1520 rasops_emul.eraserows(ri, row, nrow, attr); 1521 dc->dc_state &= ~HPCFB_DC_DRAWING; 1522 #ifdef HPCFB_JUMP 1523 hpcfb_check_update(dc); 1524 #endif /* HPCFB_JUMP */ 1525 } 1526 1527 /* 1528 * allocattr 1529 */ 1530 int 1531 hpcfb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp) 1532 { 1533 struct hpcfb_devconfig *dc = (struct hpcfb_devconfig *)cookie; 1534 struct rasops_info *ri = &dc->dc_rinfo; 1535 1536 return (rasops_emul.allocattr(ri, fg, bg, flags, attrp)); 1537 } 1538