1 /* $NetBSD: tfb.c,v 1.30 2001/08/05 18:07:55 jdolecek Exp $ */ 2 3 /* 4 * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Tohru Nishimura 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 34 35 __KERNEL_RCSID(0, "$NetBSD: tfb.c,v 1.30 2001/08/05 18:07:55 jdolecek Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/device.h> 41 #include <sys/malloc.h> 42 #include <sys/buf.h> 43 #include <sys/ioctl.h> 44 45 #include <machine/bus.h> 46 #include <machine/intr.h> 47 48 #include <dev/wscons/wsconsio.h> 49 #include <dev/wscons/wsdisplayvar.h> 50 51 #include <dev/rasops/rasops.h> 52 #include <dev/wsfont/wsfont.h> 53 54 #include <dev/tc/tcvar.h> 55 #include <dev/ic/bt463reg.h> 56 #include <dev/ic/bt431reg.h> 57 58 #include <uvm/uvm_extern.h> 59 60 #if defined(pmax) 61 #define machine_btop(x) mips_btop(x) 62 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x) 63 64 /* 65 * struct bt463reg { 66 * u_int8_t bt_lo; 67 * unsigned : 24; 68 * u_int8_t bt_hi; 69 * unsigned : 24; 70 * u_int8_t bt_reg; 71 * unsigned : 24; 72 * u_int8_t bt_cmap; 73 * }; 74 * 75 * N.B. a pair of Bt431s are located adjascently. 76 * struct bt431twin { 77 * struct { 78 * u_int8_t u0; for sprite mask 79 * u_int8_t u1; for sprite image 80 * unsigned :16; 81 * } bt_lo; 82 * ... 83 * 84 * struct bt431reg { 85 * u_int16_t bt_lo; 86 * unsigned : 16; 87 * u_int16_t bt_hi; 88 * unsigned : 16; 89 * u_int16_t bt_ram; 90 * unsigned : 16; 91 * u_int16_t bt_ctl; 92 * }; 93 */ 94 95 #define BYTE(base, index) *((u_int8_t *)(base) + ((index)<<2)) 96 #define HALF(base, index) *((u_int16_t *)(base) + ((index)<<1)) 97 98 #endif 99 100 #if defined(alpha) 101 #define machine_btop(x) alpha_btop(x) 102 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x) 103 104 /* 105 * struct bt463reg { 106 * u_int32_t bt_lo; 107 * u_int32_t bt_hi; 108 * u_int32_t bt_reg; 109 * u_int32_t bt_cmap; 110 * }; 111 * 112 * struct bt431reg { 113 * u_int32_t bt_lo; 114 * u_int32_t bt_hi; 115 * u_int32_t bt_ram; 116 * u_int32_t bt_ctl; 117 * }; 118 */ 119 120 #define BYTE(base, index) *((u_int32_t *)(base) + (index)) 121 #define HALF(base, index) *((u_int32_t *)(base) + (index)) 122 123 #endif 124 125 /* Bt463 hardware registers */ 126 #define bt_lo 0 127 #define bt_hi 1 128 #define bt_reg 2 129 #define bt_cmap 3 130 131 /* Bt431 hardware registers */ 132 #define bt_ram 2 133 #define bt_ctl 3 134 135 #define SELECT463(vdac, regno) do { \ 136 BYTE(vdac, bt_lo) = (regno) & 0x00ff; \ 137 BYTE(vdac, bt_hi) = ((regno)& 0xff00) >> 8; \ 138 tc_wmb(); \ 139 } while (0) 140 141 #define TWIN(x) ((x) | ((x) << 8)) 142 #define TWIN_LO(x) (twin = (x) & 0x00ff, (twin << 8) | twin) 143 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | (twin >> 8)) 144 145 #define SELECT431(curs, regno) do { \ 146 HALF(curs, bt_lo) = TWIN(regno);\ 147 HALF(curs, bt_hi) = 0; \ 148 tc_wmb(); \ 149 } while (0) 150 151 struct fb_devconfig { 152 vaddr_t dc_vaddr; /* memory space virtual base address */ 153 paddr_t dc_paddr; /* memory space physical base address */ 154 vsize_t dc_size; /* size of slot memory */ 155 int dc_wid; /* width of frame buffer */ 156 int dc_ht; /* height of frame buffer */ 157 int dc_depth; /* depth, bits per pixel */ 158 int dc_rowbytes; /* bytes in a FB scan line */ 159 vaddr_t dc_videobase; /* base of flat frame buffer */ 160 int dc_blanked; /* currently has video disabled */ 161 162 struct rasops_info rinfo; 163 }; 164 165 struct hwcmap256 { 166 #define CMAP_SIZE 256 /* R/G/B entries */ 167 u_int8_t r[CMAP_SIZE]; 168 u_int8_t g[CMAP_SIZE]; 169 u_int8_t b[CMAP_SIZE]; 170 }; 171 172 struct hwcursor64 { 173 struct wsdisplay_curpos cc_pos; 174 struct wsdisplay_curpos cc_hot; 175 struct wsdisplay_curpos cc_size; 176 struct wsdisplay_curpos cc_magic; 177 #define CURSOR_MAX_SIZE 64 178 u_int8_t cc_color[6]; 179 u_int64_t cc_image[64 + 64]; 180 }; 181 182 struct tfb_softc { 183 struct device sc_dev; 184 struct fb_devconfig *sc_dc; /* device configuration */ 185 struct hwcmap256 sc_cmap; /* software copy of colormap */ 186 struct hwcursor64 sc_cursor; /* software copy of cursor */ 187 int sc_curenb; /* cursor sprite enabled */ 188 int sc_changed; /* need update of hardware */ 189 #define WSDISPLAY_CMAP_DOLUT 0x20 190 int nscreens; 191 }; 192 193 #define TX_MAGIC_X 360 194 #define TX_MAGIC_Y 36 195 196 #define TX_BT463_OFFSET 0x040000 197 #define TX_BT431_OFFSET 0x040010 198 #define TX_CONTROL 0x040030 199 #define TX_MAP_REGISTER 0x040030 200 #define TX_PIP_OFFSET 0x0800c0 201 #define TX_SELECTION 0x100000 202 #define TX_8BPP_OFFSET 0x200000 203 #define TX_8BPP_SIZE 0x200000 204 #define TX_24BPP_OFFSET 0x400000 205 #define TX_24BPP_SIZE 0x600000 206 #define TX_VIDEO_ENABLE 0xa00000 207 208 #define TX_CTL_VIDEO_ON 0x80 209 #define TX_CTL_INT_ENA 0x40 210 #define TX_CTL_INT_PEND 0x20 211 #define TX_CTL_SEG_ENA 0x10 212 #define TX_CTL_SEG 0x0f 213 214 static int tfbmatch __P((struct device *, struct cfdata *, void *)); 215 static void tfbattach __P((struct device *, struct device *, void *)); 216 217 const struct cfattach tfb_ca = { 218 sizeof(struct tfb_softc), tfbmatch, tfbattach, 219 }; 220 221 static void tfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *)); 222 static struct fb_devconfig tfb_console_dc; 223 static tc_addr_t tfb_consaddr; 224 225 static struct wsscreen_descr tfb_stdscreen = { 226 "std", 0, 0, 227 0, /* textops */ 228 0, 0, 229 WSSCREEN_REVERSE 230 }; 231 232 static const struct wsscreen_descr *_tfb_scrlist[] = { 233 &tfb_stdscreen, 234 }; 235 236 static const struct wsscreen_list tfb_screenlist = { 237 sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist 238 }; 239 240 static int tfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 241 static paddr_t tfbmmap __P((void *, off_t, int)); 242 243 static int tfb_alloc_screen __P((void *, const struct wsscreen_descr *, 244 void **, int *, int *, long *)); 245 static void tfb_free_screen __P((void *, void *)); 246 static int tfb_show_screen __P((void *, void *, int, 247 void (*) (void *, int, int), void *)); 248 249 static const struct wsdisplay_accessops tfb_accessops = { 250 tfbioctl, 251 tfbmmap, 252 tfb_alloc_screen, 253 tfb_free_screen, 254 tfb_show_screen, 255 0 /* load_font */ 256 }; 257 258 int tfb_cnattach __P((tc_addr_t)); 259 static int tfbintr __P((void *)); 260 static void tfbinit __P((struct fb_devconfig *)); 261 262 static int get_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *)); 263 static int set_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *)); 264 static int set_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *)); 265 static int get_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *)); 266 static void set_curpos __P((struct tfb_softc *, struct wsdisplay_curpos *)); 267 268 /* bit order reverse */ 269 static const u_int8_t flip[256] = { 270 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 271 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 272 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 273 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 274 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 275 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 276 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 277 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 278 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 279 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 280 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 281 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 282 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 283 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 284 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 285 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 286 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 287 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 288 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 289 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 290 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 291 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 292 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 293 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 294 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 295 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 296 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 297 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 298 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 299 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 300 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 301 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 302 }; 303 304 static int 305 tfbmatch(parent, match, aux) 306 struct device *parent; 307 struct cfdata *match; 308 void *aux; 309 { 310 struct tc_attach_args *ta = aux; 311 312 if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0 313 && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0) 314 return (0); 315 316 return (1); 317 } 318 319 static void 320 tfb_getdevconfig(dense_addr, dc) 321 tc_addr_t dense_addr; 322 struct fb_devconfig *dc; 323 { 324 int i, cookie; 325 326 dc->dc_vaddr = dense_addr; 327 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr); 328 329 dc->dc_wid = 1280; 330 dc->dc_ht = 1024; 331 dc->dc_depth = 8; 332 dc->dc_rowbytes = 1280; 333 dc->dc_videobase = dc->dc_vaddr + TX_8BPP_OFFSET; 334 dc->dc_blanked = 0; 335 336 /* initialize colormap and cursor resource */ 337 tfbinit(dc); 338 339 /* clear the screen */ 340 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 341 *(u_int32_t *)(dc->dc_videobase + i) = 0x0; 342 343 dc->rinfo.ri_flg = RI_CENTER; 344 dc->rinfo.ri_depth = dc->dc_depth; 345 dc->rinfo.ri_bits = (void *)dc->dc_videobase; 346 dc->rinfo.ri_width = dc->dc_wid; 347 dc->rinfo.ri_height = dc->dc_ht; 348 dc->rinfo.ri_stride = dc->dc_rowbytes; 349 350 wsfont_init(); 351 /* prefer 8 pixel wide font */ 352 if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0) 353 cookie = wsfont_find(NULL, 0, 0, 0); 354 if (cookie <= 0) { 355 printf("tfb: font table is empty\n"); 356 return; 357 } 358 359 if (wsfont_lock(cookie, &dc->rinfo.ri_font, 360 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) { 361 printf("tfb: couldn't lock font\n"); 362 return; 363 } 364 dc->rinfo.ri_wsfcookie = cookie; 365 366 rasops_init(&dc->rinfo, 34, 80); 367 368 /* XXX shouldn't be global */ 369 tfb_stdscreen.nrows = dc->rinfo.ri_rows; 370 tfb_stdscreen.ncols = dc->rinfo.ri_cols; 371 tfb_stdscreen.textops = &dc->rinfo.ri_ops; 372 tfb_stdscreen.capabilities = dc->rinfo.ri_caps; 373 } 374 375 static void 376 tfbattach(parent, self, aux) 377 struct device *parent, *self; 378 void *aux; 379 { 380 struct tfb_softc *sc = (struct tfb_softc *)self; 381 struct tc_attach_args *ta = aux; 382 struct wsemuldisplaydev_attach_args waa; 383 struct hwcmap256 *cm; 384 const u_int8_t *p; 385 int console, index; 386 387 console = (ta->ta_addr == tfb_consaddr); 388 if (console) { 389 sc->sc_dc = &tfb_console_dc; 390 sc->nscreens = 1; 391 } 392 else { 393 sc->sc_dc = (struct fb_devconfig *) 394 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK); 395 tfb_getdevconfig(ta->ta_addr, sc->sc_dc); 396 } 397 printf(": %d x %d, 8,24bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht); 398 399 cm = &sc->sc_cmap; 400 p = rasops_cmap; 401 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 402 cm->r[index] = p[0]; 403 cm->g[index] = p[1]; 404 cm->b[index] = p[2]; 405 } 406 407 sc->sc_cursor.cc_magic.x = TX_MAGIC_X; 408 sc->sc_cursor.cc_magic.y = TX_MAGIC_Y; 409 410 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, tfbintr, sc); 411 412 *(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40; 413 *(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40; 414 415 waa.console = console; 416 waa.scrdata = &tfb_screenlist; 417 waa.accessops = &tfb_accessops; 418 waa.accesscookie = sc; 419 420 config_found(self, &waa, wsemuldisplaydevprint); 421 } 422 423 static int 424 tfbioctl(v, cmd, data, flag, p) 425 void *v; 426 u_long cmd; 427 caddr_t data; 428 int flag; 429 struct proc *p; 430 { 431 struct tfb_softc *sc = v; 432 struct fb_devconfig *dc = sc->sc_dc; 433 int turnoff; 434 435 switch (cmd) { 436 case WSDISPLAYIO_GTYPE: 437 *(u_int *)data = WSDISPLAY_TYPE_TX; 438 return (0); 439 440 case WSDISPLAYIO_GINFO: 441 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 442 wsd_fbip->height = sc->sc_dc->dc_ht; 443 wsd_fbip->width = sc->sc_dc->dc_wid; 444 wsd_fbip->depth = sc->sc_dc->dc_depth; 445 wsd_fbip->cmsize = CMAP_SIZE; 446 #undef fbt 447 return (0); 448 449 case WSDISPLAYIO_GETCMAP: 450 return get_cmap(sc, (struct wsdisplay_cmap *)data); 451 452 case WSDISPLAYIO_PUTCMAP: 453 return set_cmap(sc, (struct wsdisplay_cmap *)data); 454 455 case WSDISPLAYIO_SVIDEO: 456 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 457 if ((dc->dc_blanked == 0) ^ turnoff) { 458 dc->dc_blanked = turnoff; 459 #if 0 /* XXX later XXX */ 460 To turn off; 461 - clear the MSB of TX control register; &= ~0x80, 462 - assign Bt431 register #0 with value 0x4 to hide sprite cursor. 463 #endif /* XXX XXX XXX */ 464 } 465 return (0); 466 467 case WSDISPLAYIO_GVIDEO: 468 *(u_int *)data = dc->dc_blanked ? 469 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 470 return (0); 471 472 case WSDISPLAYIO_GCURPOS: 473 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 474 return (0); 475 476 case WSDISPLAYIO_SCURPOS: 477 set_curpos(sc, (struct wsdisplay_curpos *)data); 478 sc->sc_changed = WSDISPLAY_CURSOR_DOPOS; 479 return (0); 480 481 case WSDISPLAYIO_GCURMAX: 482 ((struct wsdisplay_curpos *)data)->x = 483 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 484 return (0); 485 486 case WSDISPLAYIO_GCURSOR: 487 return get_cursor(sc, (struct wsdisplay_cursor *)data); 488 489 case WSDISPLAYIO_SCURSOR: 490 return set_cursor(sc, (struct wsdisplay_cursor *)data); 491 } 492 return (ENOTTY); 493 } 494 495 static paddr_t 496 tfbmmap(v, offset, prot) 497 void *v; 498 off_t offset; 499 int prot; 500 { 501 struct tfb_softc *sc = v; 502 503 if (offset >= TX_8BPP_SIZE || offset < 0) 504 return (-1); 505 return machine_btop(sc->sc_dc->dc_paddr + TX_8BPP_OFFSET + offset); 506 } 507 508 static int 509 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 510 void *v; 511 const struct wsscreen_descr *type; 512 void **cookiep; 513 int *curxp, *curyp; 514 long *attrp; 515 { 516 struct tfb_softc *sc = v; 517 long defattr; 518 519 if (sc->nscreens > 0) 520 return (ENOMEM); 521 522 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */ 523 *curxp = 0; 524 *curyp = 0; 525 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr); 526 *attrp = defattr; 527 sc->nscreens++; 528 return (0); 529 } 530 531 static void 532 tfb_free_screen(v, cookie) 533 void *v; 534 void *cookie; 535 { 536 struct tfb_softc *sc = v; 537 538 if (sc->sc_dc == &tfb_console_dc) 539 panic("tfb_free_screen: console"); 540 541 sc->nscreens--; 542 } 543 544 static int 545 tfb_show_screen(v, cookie, waitok, cb, cbarg) 546 void *v; 547 void *cookie; 548 int waitok; 549 void (*cb) __P((void *, int, int)); 550 void *cbarg; 551 { 552 553 return (0); 554 } 555 556 /* EXPORT */ int 557 tfb_cnattach(addr) 558 tc_addr_t addr; 559 { 560 struct fb_devconfig *dcp = &tfb_console_dc; 561 long defattr; 562 563 tfb_getdevconfig(addr, dcp); 564 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr); 565 wsdisplay_cnattach(&tfb_stdscreen, &dcp->rinfo, 0, 0, defattr); 566 tfb_consaddr = addr; 567 return (0); 568 } 569 570 static int 571 tfbintr(arg) 572 void *arg; 573 { 574 struct tfb_softc *sc = arg; 575 caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 576 void *vdac, *curs; 577 int v; 578 579 *(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40; 580 if (sc->sc_changed == 0) 581 goto done; 582 583 vdac = (void *)(tfbbase + TX_BT463_OFFSET); 584 curs = (void *)(tfbbase + TX_BT431_OFFSET); 585 v = sc->sc_changed; 586 if (v & WSDISPLAY_CURSOR_DOCUR) { 587 SELECT431(curs, BT431_REG_COMMAND); 588 HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404; 589 } 590 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 591 int x, y; 592 u_int16_t twin; 593 594 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 595 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 596 597 x += sc->sc_cursor.cc_magic.x; 598 y += sc->sc_cursor.cc_magic.y; 599 600 SELECT431(curs, BT431_REG_CURSOR_X_LOW); 601 HALF(curs, bt_ctl) = TWIN_LO(x); tc_wmb(); 602 HALF(curs, bt_ctl) = TWIN_HI(x); tc_wmb(); 603 HALF(curs, bt_ctl) = TWIN_LO(y); tc_wmb(); 604 HALF(curs, bt_ctl) = TWIN_HI(y); tc_wmb(); 605 } 606 if (v & WSDISPLAY_CURSOR_DOCMAP) { 607 u_int8_t *cp = sc->sc_cursor.cc_color; 608 609 SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0); 610 BYTE(vdac, bt_reg) = cp[1]; tc_wmb(); 611 BYTE(vdac, bt_reg) = cp[3]; tc_wmb(); 612 BYTE(vdac, bt_reg) = cp[5]; tc_wmb(); 613 614 BYTE(vdac, bt_reg) = cp[0]; tc_wmb(); 615 BYTE(vdac, bt_reg) = cp[2]; tc_wmb(); 616 BYTE(vdac, bt_reg) = cp[4]; tc_wmb(); 617 618 BYTE(vdac, bt_reg) = cp[1]; tc_wmb(); 619 BYTE(vdac, bt_reg) = cp[3]; tc_wmb(); 620 BYTE(vdac, bt_reg) = cp[5]; tc_wmb(); 621 622 BYTE(vdac, bt_reg) = cp[1]; tc_wmb(); 623 BYTE(vdac, bt_reg) = cp[3]; tc_wmb(); 624 BYTE(vdac, bt_reg) = cp[5]; tc_wmb(); 625 } 626 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 627 u_int8_t *ip, *mp, img, msk; 628 int bcnt; 629 630 ip = (u_int8_t *)sc->sc_cursor.cc_image; 631 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE); 632 bcnt = 0; 633 SELECT431(curs, BT431_REG_CRAM_BASE); 634 635 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 636 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 637 /* pad right half 32 pixel when smaller than 33 */ 638 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 639 HALF(curs, bt_ram) = 0; 640 tc_wmb(); 641 } 642 else { 643 img = *ip++; 644 msk = *mp++; 645 img &= msk; /* cookie off image */ 646 HALF(curs, bt_ram) 647 = (flip[img] << 8) | flip[msk]; 648 tc_wmb(); 649 } 650 bcnt += 2; 651 } 652 /* pad unoccupied scan lines */ 653 while (bcnt < CURSOR_MAX_SIZE * 16) { 654 HALF(curs, bt_ram) = 0; 655 tc_wmb(); 656 bcnt += 2; 657 } 658 } 659 if (v & WSDISPLAY_CMAP_DOLUT) { 660 struct hwcmap256 *cm = &sc->sc_cmap; 661 int index; 662 663 SELECT463(vdac, BT463_IREG_CPALETTE_RAM); 664 for (index = 0; index < CMAP_SIZE; index++) { 665 BYTE(vdac, bt_cmap) = cm->r[index]; 666 BYTE(vdac, bt_cmap) = cm->g[index]; 667 BYTE(vdac, bt_cmap) = cm->b[index]; 668 } 669 } 670 sc->sc_changed = 0; 671 done: 672 *(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40; /* !? Eeeh !? */ 673 *(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40; 674 return (1); 675 } 676 677 static void 678 tfbinit(dc) 679 struct fb_devconfig *dc; 680 { 681 caddr_t tfbbase = (caddr_t)dc->dc_vaddr; 682 void *vdac = (void *)(tfbbase + TX_BT463_OFFSET); 683 void *curs = (void *)(tfbbase + TX_BT431_OFFSET); 684 const u_int8_t *p; 685 int i; 686 687 SELECT463(vdac, BT463_IREG_COMMAND_0); 688 BYTE(vdac, bt_reg) = 0x40; tc_wmb(); /* CMD 0 */ 689 BYTE(vdac, bt_reg) = 0x46; tc_wmb(); /* CMD 1 */ 690 BYTE(vdac, bt_reg) = 0xc0; tc_wmb(); /* CMD 2 */ 691 BYTE(vdac, bt_reg) = 0; tc_wmb(); /* !? 204 !? */ 692 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 0:7 */ 693 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 8:15 */ 694 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 16:23 */ 695 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 24:27 */ 696 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 0:7 */ 697 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 8:15 */ 698 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 16:23 */ 699 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 24:27 */ 700 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); 701 702 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */ 703 { 704 static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = { 705 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 706 }; 707 708 SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE); 709 for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) { 710 BYTE(vdac, bt_reg) = windowtype[i]; /* 0:7 */ 711 BYTE(vdac, bt_reg) = windowtype[i] >> 8; /* 8:15 */ 712 BYTE(vdac, bt_reg) = windowtype[i] >> 16; /* 16:23 */ 713 } 714 } 715 #endif 716 717 SELECT463(vdac, BT463_IREG_CPALETTE_RAM); 718 p = rasops_cmap; 719 for (i = 0; i < 256; i++, p += 3) { 720 BYTE(vdac, bt_cmap) = p[0]; tc_wmb(); 721 BYTE(vdac, bt_cmap) = p[1]; tc_wmb(); 722 BYTE(vdac, bt_cmap) = p[2]; tc_wmb(); 723 } 724 725 /* !? Eeeh !? */ 726 SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */); 727 for (i = 0; i < 256; i++) { 728 BYTE(vdac, bt_cmap) = i; tc_wmb(); 729 BYTE(vdac, bt_cmap) = i; tc_wmb(); 730 BYTE(vdac, bt_cmap) = i; tc_wmb(); 731 } 732 733 SELECT431(curs, BT431_REG_COMMAND); 734 HALF(curs, bt_ctl) = 0x0404; tc_wmb(); 735 HALF(curs, bt_ctl) = 0; /* XLO */ tc_wmb(); 736 HALF(curs, bt_ctl) = 0; /* XHI */ tc_wmb(); 737 HALF(curs, bt_ctl) = 0; /* YLO */ tc_wmb(); 738 HALF(curs, bt_ctl) = 0; /* YHI */ tc_wmb(); 739 HALF(curs, bt_ctl) = 0; /* XWLO */ tc_wmb(); 740 HALF(curs, bt_ctl) = 0; /* XWHI */ tc_wmb(); 741 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb(); 742 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb(); 743 HALF(curs, bt_ctl) = 0; /* WWLO */ tc_wmb(); 744 HALF(curs, bt_ctl) = 0; /* WWHI */ tc_wmb(); 745 HALF(curs, bt_ctl) = 0; /* WHLO */ tc_wmb(); 746 HALF(curs, bt_ctl) = 0; /* WHHI */ tc_wmb(); 747 748 SELECT431(curs, BT431_REG_CRAM_BASE); 749 for (i = 0; i < 512; i++) { 750 HALF(curs, bt_ram) = 0; tc_wmb(); 751 } 752 } 753 754 static int 755 get_cmap(sc, p) 756 struct tfb_softc *sc; 757 struct wsdisplay_cmap *p; 758 { 759 u_int index = p->index, count = p->count; 760 761 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 762 return (EINVAL); 763 764 if (!uvm_useracc(p->red, count, B_WRITE) || 765 !uvm_useracc(p->green, count, B_WRITE) || 766 !uvm_useracc(p->blue, count, B_WRITE)) 767 return (EFAULT); 768 769 copyout(&sc->sc_cmap.r[index], p->red, count); 770 copyout(&sc->sc_cmap.g[index], p->green, count); 771 copyout(&sc->sc_cmap.b[index], p->blue, count); 772 773 return (0); 774 } 775 776 static int 777 set_cmap(sc, p) 778 struct tfb_softc *sc; 779 struct wsdisplay_cmap *p; 780 { 781 u_int index = p->index, count = p->count; 782 783 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 784 return (EINVAL); 785 786 if (!uvm_useracc(p->red, count, B_READ) || 787 !uvm_useracc(p->green, count, B_READ) || 788 !uvm_useracc(p->blue, count, B_READ)) 789 return (EFAULT); 790 791 copyin(p->red, &sc->sc_cmap.r[index], count); 792 copyin(p->green, &sc->sc_cmap.g[index], count); 793 copyin(p->blue, &sc->sc_cmap.b[index], count); 794 795 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT; 796 797 return (0); 798 } 799 800 static int 801 set_cursor(sc, p) 802 struct tfb_softc *sc; 803 struct wsdisplay_cursor *p; 804 { 805 #define cc (&sc->sc_cursor) 806 u_int v, index, count, icount; 807 808 v = p->which; 809 if (v & WSDISPLAY_CURSOR_DOCMAP) { 810 index = p->cmap.index; 811 count = p->cmap.count; 812 if (index >= 2 || (index + count) > 2) 813 return (EINVAL); 814 if (!uvm_useracc(p->cmap.red, count, B_READ) || 815 !uvm_useracc(p->cmap.green, count, B_READ) || 816 !uvm_useracc(p->cmap.blue, count, B_READ)) 817 return (EFAULT); 818 } 819 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 820 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 821 return (EINVAL); 822 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 823 if (!uvm_useracc(p->image, icount, B_READ) || 824 !uvm_useracc(p->mask, icount, B_READ)) 825 return (EFAULT); 826 } 827 828 if (v & WSDISPLAY_CURSOR_DOCUR) 829 sc->sc_curenb = p->enable; 830 if (v & WSDISPLAY_CURSOR_DOPOS) 831 set_curpos(sc, &p->pos); 832 if (v & WSDISPLAY_CURSOR_DOHOT) 833 cc->cc_hot = p->hot; 834 if (v & WSDISPLAY_CURSOR_DOCMAP) { 835 copyin(p->cmap.red, &cc->cc_color[index], count); 836 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 837 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 838 } 839 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 840 cc->cc_size = p->size; 841 memset(cc->cc_image, 0, sizeof cc->cc_image); 842 copyin(p->image, cc->cc_image, icount); 843 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount); 844 } 845 sc->sc_changed = v; 846 847 return (0); 848 #undef cc 849 } 850 851 static int 852 get_cursor(sc, p) 853 struct tfb_softc *sc; 854 struct wsdisplay_cursor *p; 855 { 856 return (ENOTTY); /* XXX */ 857 } 858 859 static void 860 set_curpos(sc, curpos) 861 struct tfb_softc *sc; 862 struct wsdisplay_curpos *curpos; 863 { 864 struct fb_devconfig *dc = sc->sc_dc; 865 int x = curpos->x, y = curpos->y; 866 867 if (y < 0) 868 y = 0; 869 else if (y > dc->dc_ht) 870 y = dc->dc_ht; 871 if (x < 0) 872 x = 0; 873 else if (x > dc->dc_wid) 874 x = dc->dc_wid; 875 sc->sc_cursor.cc_pos.x = x; 876 sc->sc_cursor.cc_pos.y = y; 877 } 878