1 /* $NetBSD: mfb.c,v 1.26 2001/01/16 05:32:16 nisimura 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: mfb.c,v 1.26 2001/01/16 05:32:16 nisimura 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/bt431reg.h> 56 57 #include <uvm/uvm_extern.h> 58 59 #if defined(pmax) 60 #define machine_btop(x) mips_btop(x) 61 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x) 62 63 #define BYTE(base, index) *((u_int8_t *)(base) + ((index)<<2)) 64 #define HALF(base, index) *((u_int16_t *)(base) + ((index)<<1)) 65 #endif 66 67 #if defined(__alpha__) || defined(alpha) 68 #define machine_btop(x) alpha_btop(x) 69 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x) 70 71 #define BYTE(base, index) *((u_int32_t *)(base) + (index)) 72 #define HALF(base, index) *((u_int32_t *)(base) + (index)) 73 #endif 74 75 /* Bt455 hardware registers */ 76 #define bt_reg 0 77 #define bt_cmap 1 78 #define bt_clr 2 79 #define bt_ovly 3 80 81 /* Bt431 hardware registers */ 82 #define bt_lo 0 83 #define bt_hi 1 84 #define bt_ram 2 85 #define bt_ctl 3 86 87 #define SELECT455(vdac, regno) do { \ 88 BYTE(vdac, bt_reg) = (regno); \ 89 BYTE(vdac, bt_clr) = 0; \ 90 tc_wmb(); \ 91 } while (0) 92 93 #define TWIN(x) ((x)|((x) << 8)) 94 #define TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin) 95 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8) 96 97 #define SELECT431(curs, regno) do { \ 98 HALF(curs, bt_lo) = TWIN(regno);\ 99 HALF(curs, bt_hi) = 0; \ 100 tc_wmb(); \ 101 } while (0) 102 103 104 struct fb_devconfig { 105 vaddr_t dc_vaddr; /* memory space virtual base address */ 106 paddr_t dc_paddr; /* memory space physical base address */ 107 vsize_t dc_size; /* size of slot memory */ 108 int dc_wid; /* width of frame buffer */ 109 int dc_ht; /* height of frame buffer */ 110 int dc_depth; /* depth, bits per pixel */ 111 int dc_rowbytes; /* bytes in a FB scan line */ 112 vaddr_t dc_videobase; /* base of flat frame buffer */ 113 int dc_blanked; /* currently has video disabled */ 114 115 struct rasops_info rinfo; 116 }; 117 118 struct hwcursor64 { 119 struct wsdisplay_curpos cc_pos; 120 struct wsdisplay_curpos cc_hot; 121 struct wsdisplay_curpos cc_size; 122 struct wsdisplay_curpos cc_magic; 123 #define CURSOR_MAX_SIZE 64 124 u_int8_t cc_color[6]; 125 u_int64_t cc_image[64 + 64]; 126 }; 127 128 struct mfb_softc { 129 struct device sc_dev; 130 struct fb_devconfig *sc_dc; /* device configuration */ 131 struct hwcursor64 sc_cursor; /* software copy of cursor */ 132 int sc_curenb; /* cursor sprite enabled */ 133 int sc_changed; /* need update of hardware */ 134 int nscreens; 135 }; 136 137 #define MX_MAGIC_X 360 138 #define MX_MAGIC_Y 36 139 140 #define MX_FB_OFFSET 0x200000 141 #define MX_FB_SIZE 0x200000 142 #define MX_BT455_OFFSET 0x100000 143 #define MX_BT431_OFFSET 0x180000 144 #define MX_IREQ_OFFSET 0x080000 /* Interrupt req. control */ 145 146 static int mfbmatch __P((struct device *, struct cfdata *, void *)); 147 static void mfbattach __P((struct device *, struct device *, void *)); 148 149 const struct cfattach mfb_ca = { 150 sizeof(struct mfb_softc), mfbmatch, mfbattach, 151 }; 152 153 static void mfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *)); 154 static struct fb_devconfig mfb_console_dc; 155 static tc_addr_t mfb_consaddr; 156 157 static struct wsscreen_descr mfb_stdscreen = { 158 "std", 0, 0, 159 0, /* textops */ 160 0, 0, 161 WSSCREEN_REVERSE 162 }; 163 164 static const struct wsscreen_descr *_mfb_scrlist[] = { 165 &mfb_stdscreen, 166 }; 167 168 static const struct wsscreen_list mfb_screenlist = { 169 sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist 170 }; 171 172 static int mfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 173 static paddr_t mfbmmap __P((void *, off_t, int)); 174 175 static int mfb_alloc_screen __P((void *, const struct wsscreen_descr *, 176 void **, int *, int *, long *)); 177 static void mfb_free_screen __P((void *, void *)); 178 static int mfb_show_screen __P((void *, void *, int, 179 void (*) (void *, int, int), void *)); 180 181 static const struct wsdisplay_accessops mfb_accessops = { 182 mfbioctl, 183 mfbmmap, 184 mfb_alloc_screen, 185 mfb_free_screen, 186 mfb_show_screen, 187 0 /* load_font */ 188 }; 189 190 int mfb_cnattach __P((tc_addr_t)); 191 static int mfbintr __P((void *)); 192 static void mfbinit __P((struct fb_devconfig *)); 193 194 static int set_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *)); 195 static int get_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *)); 196 static void set_curpos __P((struct mfb_softc *, struct wsdisplay_curpos *)); 197 198 /* bit order reverse */ 199 static const u_int8_t flip[256] = { 200 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 201 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 202 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 203 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 204 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 205 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 206 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 207 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 208 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 209 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 210 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 211 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 212 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 213 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 214 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 215 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 216 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 217 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 218 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 219 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 220 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 221 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 222 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 223 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 224 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 225 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 226 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 227 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 228 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 229 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 230 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 231 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 232 }; 233 234 static int 235 mfbmatch(parent, match, aux) 236 struct device *parent; 237 struct cfdata *match; 238 void *aux; 239 { 240 struct tc_attach_args *ta = aux; 241 242 if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0) 243 return (0); 244 245 return (1); 246 } 247 248 static void 249 mfb_getdevconfig(dense_addr, dc) 250 tc_addr_t dense_addr; 251 struct fb_devconfig *dc; 252 { 253 int i, cookie; 254 255 dc->dc_vaddr = dense_addr; 256 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + MX_FB_OFFSET); 257 258 dc->dc_wid = 1280; 259 dc->dc_ht = 1024; 260 dc->dc_depth = 8; 261 dc->dc_rowbytes = 2048; 262 dc->dc_videobase = dc->dc_vaddr + MX_FB_OFFSET; 263 dc->dc_blanked = 0; 264 265 /* initialize colormap and cursor resource */ 266 mfbinit(dc); 267 268 /* clear the screen */ 269 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 270 *(u_int32_t *)(dc->dc_videobase + i) = 0; 271 272 dc->rinfo.ri_flg = RI_CENTER; 273 dc->rinfo.ri_depth = dc->dc_depth; 274 dc->rinfo.ri_bits = (void *)dc->dc_videobase; 275 dc->rinfo.ri_width = dc->dc_wid; 276 dc->rinfo.ri_height = dc->dc_ht; 277 dc->rinfo.ri_stride = dc->dc_rowbytes; 278 279 wsfont_init(); 280 /* prefer 8 pixel wide font */ 281 if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0) 282 cookie = wsfont_find(NULL, 0, 0, 0); 283 if (cookie <= 0) { 284 printf("mfb: font table is empty\n"); 285 return; 286 } 287 288 if (wsfont_lock(cookie, &dc->rinfo.ri_font, 289 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) { 290 printf("mfb: couldn't lock font\n"); 291 return; 292 } 293 dc->rinfo.ri_wsfcookie = cookie; 294 295 rasops_init(&dc->rinfo, 34, 80); 296 297 /* XXX shouldn't be global */ 298 mfb_stdscreen.nrows = dc->rinfo.ri_rows; 299 mfb_stdscreen.ncols = dc->rinfo.ri_cols; 300 mfb_stdscreen.textops = &dc->rinfo.ri_ops; 301 mfb_stdscreen.capabilities = dc->rinfo.ri_caps; 302 } 303 304 static void 305 mfbattach(parent, self, aux) 306 struct device *parent, *self; 307 void *aux; 308 { 309 struct mfb_softc *sc = (struct mfb_softc *)self; 310 struct tc_attach_args *ta = aux; 311 struct wsemuldisplaydev_attach_args waa; 312 caddr_t mfbbase; 313 int console; 314 volatile register int junk; 315 316 console = (ta->ta_addr == mfb_consaddr); 317 if (console) { 318 sc->sc_dc = &mfb_console_dc; 319 sc->nscreens = 1; 320 } 321 else { 322 sc->sc_dc = (struct fb_devconfig *) 323 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK); 324 mfb_getdevconfig(ta->ta_addr, sc->sc_dc); 325 } 326 printf(": %d x %d, 1bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht); 327 328 sc->sc_cursor.cc_magic.x = MX_MAGIC_X; 329 sc->sc_cursor.cc_magic.y = MX_MAGIC_Y; 330 331 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc); 332 333 mfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 334 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0; 335 junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET); 336 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 1; 337 338 waa.console = console; 339 waa.scrdata = &mfb_screenlist; 340 waa.accessops = &mfb_accessops; 341 waa.accesscookie = sc; 342 343 config_found(self, &waa, wsemuldisplaydevprint); 344 } 345 346 static int 347 mfbioctl(v, cmd, data, flag, p) 348 void *v; 349 u_long cmd; 350 caddr_t data; 351 int flag; 352 struct proc *p; 353 { 354 struct mfb_softc *sc = v; 355 struct fb_devconfig *dc = sc->sc_dc; 356 int turnoff; 357 358 switch (cmd) { 359 case WSDISPLAYIO_GTYPE: 360 *(u_int *)data = WSDISPLAY_TYPE_MFB; 361 return (0); 362 363 case WSDISPLAYIO_GINFO: 364 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 365 wsd_fbip->height = sc->sc_dc->dc_ht; 366 wsd_fbip->width = sc->sc_dc->dc_wid; 367 wsd_fbip->depth = sc->sc_dc->dc_depth; 368 wsd_fbip->cmsize = 0; 369 #undef fbt 370 return (0); 371 372 case WSDISPLAYIO_GETCMAP: 373 case WSDISPLAYIO_PUTCMAP: 374 return (ENOTTY); 375 376 case WSDISPLAYIO_SVIDEO: 377 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 378 if ((dc->dc_blanked == 0) ^ turnoff) { 379 dc->dc_blanked = turnoff; 380 #if 0 /* XXX later XXX */ 381 To turn off, 382 - assign Bt455 cmap[1].green with value 0 (black), 383 - assign Bt431 register #0 with value 0x04 to hide sprite cursor. 384 #endif /* XXX XXX XXX */ 385 } 386 return (0); 387 388 case WSDISPLAYIO_GVIDEO: 389 *(u_int *)data = dc->dc_blanked ? 390 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 391 return (0); 392 393 case WSDISPLAYIO_GCURPOS: 394 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 395 return (0); 396 397 case WSDISPLAYIO_SCURPOS: 398 set_curpos(sc, (struct wsdisplay_curpos *)data); 399 sc->sc_changed = WSDISPLAY_CURSOR_DOPOS; 400 return (0); 401 402 case WSDISPLAYIO_GCURMAX: 403 ((struct wsdisplay_curpos *)data)->x = 404 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 405 return (0); 406 407 case WSDISPLAYIO_GCURSOR: 408 return get_cursor(sc, (struct wsdisplay_cursor *)data); 409 410 case WSDISPLAYIO_SCURSOR: 411 return set_cursor(sc, (struct wsdisplay_cursor *)data); 412 } 413 return (ENOTTY); 414 } 415 416 static paddr_t 417 mfbmmap(v, offset, prot) 418 void *v; 419 off_t offset; 420 int prot; 421 { 422 struct mfb_softc *sc = v; 423 424 if (offset >= MX_FB_SIZE || offset < 0) 425 return (-1); 426 return machine_btop(sc->sc_dc->dc_paddr + offset); 427 } 428 429 static int 430 mfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 431 void *v; 432 const struct wsscreen_descr *type; 433 void **cookiep; 434 int *curxp, *curyp; 435 long *attrp; 436 { 437 struct mfb_softc *sc = v; 438 long defattr; 439 440 if (sc->nscreens > 0) 441 return (ENOMEM); 442 443 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */ 444 *curxp = 0; 445 *curyp = 0; 446 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr); 447 *attrp = defattr; 448 sc->nscreens++; 449 return (0); 450 } 451 452 static void 453 mfb_free_screen(v, cookie) 454 void *v; 455 void *cookie; 456 { 457 struct mfb_softc *sc = v; 458 459 if (sc->sc_dc == &mfb_console_dc) 460 panic("mfb_free_screen: console"); 461 462 sc->nscreens--; 463 } 464 465 static int 466 mfb_show_screen(v, cookie, waitok, cb, cbarg) 467 void *v; 468 void *cookie; 469 int waitok; 470 void (*cb) __P((void *, int, int)); 471 void *cbarg; 472 { 473 474 return (0); 475 } 476 477 /* EXPORT */ int 478 mfb_cnattach(addr) 479 tc_addr_t addr; 480 { 481 struct fb_devconfig *dcp = &mfb_console_dc; 482 long defattr; 483 484 mfb_getdevconfig(addr, dcp); 485 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr); 486 wsdisplay_cnattach(&mfb_stdscreen, &dcp->rinfo, 0, 0, defattr); 487 mfb_consaddr = addr; 488 return (0); 489 } 490 491 static int 492 mfbintr(arg) 493 void *arg; 494 { 495 struct mfb_softc *sc = arg; 496 caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 497 void *vdac, *curs; 498 int v; 499 volatile register int junk; 500 501 junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET); 502 #if 0 503 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0; 504 #endif 505 if (sc->sc_changed == 0) 506 return (1); 507 508 vdac = (void *)(mfbbase + MX_BT455_OFFSET); 509 curs = (void *)(mfbbase + MX_BT431_OFFSET); 510 v = sc->sc_changed; 511 if (v & WSDISPLAY_CURSOR_DOCUR) { 512 SELECT431(curs, BT431_REG_COMMAND); 513 HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404; 514 } 515 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 516 int x, y; 517 u_int16_t twin; 518 519 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 520 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 521 522 x += sc->sc_cursor.cc_magic.x; 523 y += sc->sc_cursor.cc_magic.y; 524 525 SELECT431(curs, BT431_REG_CURSOR_X_LOW); 526 HALF(curs, bt_ctl) = TWIN_LO(x); tc_wmb(); 527 HALF(curs, bt_ctl) = TWIN_HI(x); tc_wmb(); 528 HALF(curs, bt_ctl) = TWIN_LO(y); tc_wmb(); 529 HALF(curs, bt_ctl) = TWIN_HI(y); tc_wmb(); 530 } 531 if (v & WSDISPLAY_CURSOR_DOCMAP) { 532 u_int8_t *cp = sc->sc_cursor.cc_color; 533 534 SELECT455(vdac, 8); 535 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 536 BYTE(vdac, bt_cmap) = cp[1]; tc_wmb(); 537 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 538 539 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 540 BYTE(vdac, bt_cmap) = cp[1]; tc_wmb(); 541 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 542 543 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 544 BYTE(vdac, bt_ovly) = cp[0]; tc_wmb(); 545 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 546 } 547 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 548 u_int8_t *ip, *mp, img, msk; 549 int bcnt; 550 551 ip = (u_int8_t *)sc->sc_cursor.cc_image; 552 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE); 553 bcnt = 0; 554 SELECT431(curs, BT431_REG_CRAM_BASE); 555 556 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 557 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 558 /* pad right half 32 pixel when smaller than 33 */ 559 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 560 HALF(curs, bt_ram) = 0; 561 tc_wmb(); 562 } 563 else { 564 img = *ip++; 565 msk = *mp++; 566 img &= msk; /* cookie off image */ 567 HALF(curs, bt_ram) 568 = (flip[msk] << 8) | flip[img]; 569 tc_wmb(); 570 } 571 bcnt += 2; 572 } 573 /* pad unoccupied scan lines */ 574 while (bcnt < CURSOR_MAX_SIZE * 16) { 575 HALF(curs, bt_ram) = 0; 576 tc_wmb(); 577 bcnt += 2; 578 } 579 } 580 sc->sc_changed = 0; 581 return (1); 582 } 583 584 static void 585 mfbinit(dc) 586 struct fb_devconfig *dc; 587 { 588 caddr_t mfbbase = (caddr_t)dc->dc_vaddr; 589 void *vdac = (void *)(mfbbase + MX_BT455_OFFSET); 590 void *curs = (void *)(mfbbase + MX_BT431_OFFSET); 591 int i; 592 593 SELECT431(curs, BT431_REG_COMMAND); 594 HALF(curs, bt_ctl) = 0x0404; tc_wmb(); 595 HALF(curs, bt_ctl) = 0; /* XLO */ tc_wmb(); 596 HALF(curs, bt_ctl) = 0; /* XHI */ tc_wmb(); 597 HALF(curs, bt_ctl) = 0; /* YLO */ tc_wmb(); 598 HALF(curs, bt_ctl) = 0; /* YHI */ tc_wmb(); 599 HALF(curs, bt_ctl) = 0; /* XWLO */ tc_wmb(); 600 HALF(curs, bt_ctl) = 0; /* XWHI */ tc_wmb(); 601 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb(); 602 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb(); 603 HALF(curs, bt_ctl) = 0; /* WWLO */ tc_wmb(); 604 HALF(curs, bt_ctl) = 0; /* WWHI */ tc_wmb(); 605 HALF(curs, bt_ctl) = 0; /* WHLO */ tc_wmb(); 606 HALF(curs, bt_ctl) = 0; /* WHHI */ tc_wmb(); 607 608 /* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */ 609 SELECT455(vdac, 0); 610 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 611 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 612 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 613 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 614 BYTE(vdac, bt_cmap) = 0xff; tc_wmb(); 615 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 616 for (i = 2; i < 16; i++) { 617 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 618 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 619 BYTE(vdac, bt_cmap) = 0; tc_wmb(); 620 } 621 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 622 BYTE(vdac, bt_ovly) = 0xff; tc_wmb(); 623 BYTE(vdac, bt_ovly) = 0; tc_wmb(); 624 625 SELECT431(curs, BT431_REG_CRAM_BASE); 626 for (i = 0; i < 512; i++) { 627 HALF(curs, bt_ram) = 0; tc_wmb(); 628 } 629 } 630 631 static int 632 set_cursor(sc, p) 633 struct mfb_softc *sc; 634 struct wsdisplay_cursor *p; 635 { 636 #define cc (&sc->sc_cursor) 637 int v, count, index; 638 639 v = p->which; 640 if (v & WSDISPLAY_CURSOR_DOCMAP) { 641 index = p->cmap.index; 642 count = p->cmap.count; 643 if (index >= 2 || (index + count) > 2) 644 return (EINVAL); 645 if (!uvm_useracc(p->cmap.red, count, B_READ)) 646 return (EFAULT); 647 } 648 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 649 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 650 return (EINVAL); 651 count = ((p->size.x < 33) ? 4 : 8) * p->size.y; 652 if (!uvm_useracc(p->image, count, B_READ) || 653 !uvm_useracc(p->mask, count, B_READ)) 654 return (EFAULT); 655 } 656 657 if (v & WSDISPLAY_CURSOR_DOCUR) 658 sc->sc_curenb = p->enable; 659 if (v & WSDISPLAY_CURSOR_DOPOS) 660 set_curpos(sc, &p->pos); 661 if (v & WSDISPLAY_CURSOR_DOHOT) 662 cc->cc_hot = p->hot; 663 if (v & WSDISPLAY_CURSOR_DOCMAP) 664 copyin(p->cmap.red, &cc->cc_color[index], count); 665 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 666 cc->cc_size = p->size; 667 memset(cc->cc_image, 0, sizeof cc->cc_image); 668 copyin(p->image, cc->cc_image, count); 669 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count); 670 } 671 sc->sc_changed = v; 672 673 return (0); 674 #undef cc 675 } 676 677 static int 678 get_cursor(sc, p) 679 struct mfb_softc *sc; 680 struct wsdisplay_cursor *p; 681 { 682 return (ENOTTY); /* XXX */ 683 } 684 685 static void 686 set_curpos(sc, curpos) 687 struct mfb_softc *sc; 688 struct wsdisplay_curpos *curpos; 689 { 690 struct fb_devconfig *dc = sc->sc_dc; 691 int x = curpos->x, y = curpos->y; 692 693 if (y < 0) 694 y = 0; 695 else if (y > dc->dc_ht) 696 y = dc->dc_ht; 697 if (x < 0) 698 x = 0; 699 else if (x > dc->dc_wid) 700 x = dc->dc_wid; 701 sc->sc_cursor.cc_pos.x = x; 702 sc->sc_cursor.cc_pos.y = y; 703 } 704