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