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