cfb.c revision 1.24
1/* $NetBSD: cfb.c,v 1.24 2000/10/27 07:24:04 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: cfb.c,v 1.24 2000/10/27 07:24:04 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/bt459reg.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_KSEG1_TO_PHYS(x) 62#endif 63 64#if defined(__alpha__) || defined(alpha) 65/* 66 * Digital UNIX never supports PMAG-BA 67 */ 68#define machine_btop(x) alpha_btop(x) 69#define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x) 70#endif 71 72/* 73 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have 74 * obscure register layout such as 2nd and 3rd Bt459 registers are 75 * adjacent each other in a word, i.e., 76 * struct bt459triplet { 77 * struct { 78 * u_int8_t u0; 79 * u_int8_t u1; 80 * u_int8_t u2; 81 * unsigned :8; 82 * } bt_lo; 83 * ... 84 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble. 85 * 86 * struct bt459reg { 87 * u_int32_t bt_lo; 88 * u_int32_t bt_hi; 89 * u_int32_t bt_reg; 90 * u_int32_t bt_cmap; 91 * }; 92 * 93 */ 94 95/* Bt459 hardware registers */ 96#define bt_lo 0 97#define bt_hi 1 98#define bt_reg 2 99#define bt_cmap 3 100 101#define REG(base, index) *((u_int32_t *)(base) + (index)) 102#define SELECT(vdac, regno) do { \ 103 REG(vdac, bt_lo) = ((regno) & 0x00ff); \ 104 REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8; \ 105 tc_wmb(); \ 106 } while (0) 107 108struct fb_devconfig { 109 vaddr_t dc_vaddr; /* memory space virtual base address */ 110 paddr_t dc_paddr; /* memory space physical base address */ 111 vsize_t dc_size; /* size of slot memory */ 112 int dc_wid; /* width of frame buffer */ 113 int dc_ht; /* height of frame buffer */ 114 int dc_depth; /* depth, bits per pixel */ 115 int dc_rowbytes; /* bytes in a FB scan line */ 116 vaddr_t dc_videobase; /* base of flat frame buffer */ 117 int dc_blanked; /* currently has video disabled */ 118 119 struct rasops_info rinfo; 120}; 121 122struct hwcmap256 { 123#define CMAP_SIZE 256 /* 256 R/G/B entries */ 124 u_int8_t r[CMAP_SIZE]; 125 u_int8_t g[CMAP_SIZE]; 126 u_int8_t b[CMAP_SIZE]; 127}; 128 129struct hwcursor64 { 130 struct wsdisplay_curpos cc_pos; 131 struct wsdisplay_curpos cc_hot; 132 struct wsdisplay_curpos cc_size; 133 struct wsdisplay_curpos cc_magic; 134#define CURSOR_MAX_SIZE 64 135 u_int8_t cc_color[6]; 136 u_int64_t cc_image[64 + 64]; 137}; 138 139struct cfb_softc { 140 struct device sc_dev; 141 struct fb_devconfig *sc_dc; /* device configuration */ 142 struct hwcmap256 sc_cmap; /* software copy of colormap */ 143 struct hwcursor64 sc_cursor; /* software copy of cursor */ 144 int sc_curenb; /* cursor sprite enabled */ 145 int sc_changed; /* need update of colormap */ 146#define DATA_ENB_CHANGED 0x01 /* cursor enable changed */ 147#define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */ 148#define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */ 149#define DATA_CMAP_CHANGED 0x08 /* colormap changed */ 150#define DATA_ALL_CHANGED 0x0f 151 int nscreens; 152}; 153 154#define CX_MAGIC_X 220 155#define CX_MAGIC_Y 35 156 157#define CX_FB_OFFSET 0x000000 158#define CX_FB_SIZE 0x100000 159#define CX_BT459_OFFSET 0x200000 160#define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */ 161 162static int cfbmatch __P((struct device *, struct cfdata *, void *)); 163static void cfbattach __P((struct device *, struct device *, void *)); 164 165const struct cfattach cfb_ca = { 166 sizeof(struct cfb_softc), cfbmatch, cfbattach, 167}; 168 169static void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *)); 170static struct fb_devconfig cfb_console_dc; 171static tc_addr_t cfb_consaddr; 172 173static struct wsscreen_descr cfb_stdscreen = { 174 "std", 0, 0, 175 0, /* textops */ 176 0, 0, 177 WSSCREEN_REVERSE 178}; 179 180static const struct wsscreen_descr *_cfb_scrlist[] = { 181 &cfb_stdscreen, 182}; 183 184static const struct wsscreen_list cfb_screenlist = { 185 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist 186}; 187 188static int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 189static paddr_t cfbmmap __P((void *, off_t, int)); 190 191static int cfb_alloc_screen __P((void *, const struct wsscreen_descr *, 192 void **, int *, int *, long *)); 193static void cfb_free_screen __P((void *, void *)); 194static int cfb_show_screen __P((void *, void *, int, 195 void (*) (void *, int, int), void *)); 196 197static const struct wsdisplay_accessops cfb_accessops = { 198 cfbioctl, 199 cfbmmap, 200 cfb_alloc_screen, 201 cfb_free_screen, 202 cfb_show_screen, 203 0 /* load_font */ 204}; 205 206int cfb_cnattach __P((tc_addr_t)); 207static int cfbintr __P((void *)); 208static void cfbinit __P((struct fb_devconfig *)); 209 210static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *)); 211static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *)); 212static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *)); 213static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *)); 214static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *)); 215static void bt459_set_curpos __P((struct cfb_softc *)); 216 217/* 218 * Compose 2 bit/pixel cursor image. Bit order will be reversed. 219 * M M M M I I I I M I M I M I M I 220 * [ before ] [ after ] 221 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3 222 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7 223 */ 224static const u_int8_t shuffle[256] = { 225 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 226 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55, 227 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4, 228 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5, 229 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74, 230 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75, 231 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4, 232 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5, 233 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c, 234 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d, 235 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc, 236 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd, 237 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c, 238 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d, 239 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc, 240 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd, 241 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 242 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57, 243 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6, 244 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7, 245 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76, 246 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77, 247 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6, 248 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7, 249 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e, 250 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f, 251 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde, 252 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf, 253 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e, 254 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f, 255 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe, 256 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff, 257}; 258 259static int 260cfbmatch(parent, match, aux) 261 struct device *parent; 262 struct cfdata *match; 263 void *aux; 264{ 265 struct tc_attach_args *ta = aux; 266 267 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0) 268 return (0); 269 270 return (1); 271} 272 273static void 274cfb_getdevconfig(dense_addr, dc) 275 tc_addr_t dense_addr; 276 struct fb_devconfig *dc; 277{ 278 int i, cookie; 279 280 dc->dc_vaddr = dense_addr; 281 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET); 282 283 dc->dc_wid = 1024; 284 dc->dc_ht = 864; 285 dc->dc_depth = 8; 286 dc->dc_rowbytes = 1024; 287 dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET; 288 dc->dc_blanked = 0; 289 290 /* initialize colormap and cursor resource */ 291 cfbinit(dc); 292 293 /* clear the screen */ 294 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 295 *(u_int32_t *)(dc->dc_videobase + i) = 0x0; 296 297 dc->rinfo.ri_flg = RI_CENTER; 298 dc->rinfo.ri_depth = dc->dc_depth; 299 dc->rinfo.ri_bits = (void *)dc->dc_videobase; 300 dc->rinfo.ri_width = dc->dc_wid; 301 dc->rinfo.ri_height = dc->dc_ht; 302 dc->rinfo.ri_stride = dc->dc_rowbytes; 303 304 wsfont_init(); 305 /* prefer 8 pixel wide font */ 306 if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0) 307 cookie = wsfont_find(NULL, 0, 0, 0); 308 if (cookie <= 0) { 309 printf("cfb: font table is empty\n"); 310 return; 311 } 312 313 if (wsfont_lock(cookie, &dc->rinfo.ri_font, 314 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) { 315 printf("cfb: couldn't lock font\n"); 316 return; 317 } 318 dc->rinfo.ri_wsfcookie = cookie; 319 320 rasops_init(&dc->rinfo, 34, 80); 321 322 /* XXX shouldn't be global */ 323 cfb_stdscreen.nrows = dc->rinfo.ri_rows; 324 cfb_stdscreen.ncols = dc->rinfo.ri_cols; 325 cfb_stdscreen.textops = &dc->rinfo.ri_ops; 326 cfb_stdscreen.capabilities = dc->rinfo.ri_caps; 327} 328 329static void 330cfbattach(parent, self, aux) 331 struct device *parent, *self; 332 void *aux; 333{ 334 struct cfb_softc *sc = (struct cfb_softc *)self; 335 struct tc_attach_args *ta = aux; 336 struct wsemuldisplaydev_attach_args waa; 337 struct hwcmap256 *cm; 338 const u_int8_t *p; 339 int console, index; 340 341 console = (ta->ta_addr == cfb_consaddr); 342 if (console) { 343 sc->sc_dc = &cfb_console_dc; 344 sc->nscreens = 1; 345 } 346 else { 347 sc->sc_dc = (struct fb_devconfig *) 348 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK); 349 cfb_getdevconfig(ta->ta_addr, sc->sc_dc); 350 } 351 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht, 352 sc->sc_dc->dc_depth); 353 354 cm = &sc->sc_cmap; 355 p = rasops_cmap; 356 for (index = 0; index < CMAP_SIZE; index++) { 357 cm->r[index] = p[0]; 358 cm->g[index] = p[1]; 359 cm->b[index] = p[2]; 360 } 361 362 sc->sc_cursor.cc_magic.x = CX_MAGIC_X; 363 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y; 364 365 /* Establish an interrupt handler, and clear any pending interrupts */ 366 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc); 367 *(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0; 368 369 waa.console = console; 370 waa.scrdata = &cfb_screenlist; 371 waa.accessops = &cfb_accessops; 372 waa.accesscookie = sc; 373 374 config_found(self, &waa, wsemuldisplaydevprint); 375} 376 377static int 378cfbioctl(v, cmd, data, flag, p) 379 void *v; 380 u_long cmd; 381 caddr_t data; 382 int flag; 383 struct proc *p; 384{ 385 struct cfb_softc *sc = v; 386 struct fb_devconfig *dc = sc->sc_dc; 387 int turnoff; 388 389 switch (cmd) { 390 case WSDISPLAYIO_GTYPE: 391 *(u_int *)data = WSDISPLAY_TYPE_CFB; 392 return (0); 393 394 case WSDISPLAYIO_GINFO: 395#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 396 wsd_fbip->height = sc->sc_dc->dc_ht; 397 wsd_fbip->width = sc->sc_dc->dc_wid; 398 wsd_fbip->depth = sc->sc_dc->dc_depth; 399 wsd_fbip->cmsize = CMAP_SIZE; 400#undef fbt 401 return (0); 402 403 case WSDISPLAYIO_GETCMAP: 404 return get_cmap(sc, (struct wsdisplay_cmap *)data); 405 406 case WSDISPLAYIO_PUTCMAP: 407 return set_cmap(sc, (struct wsdisplay_cmap *)data); 408 409 case WSDISPLAYIO_SVIDEO: 410 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 411 if ((dc->dc_blanked == 0) ^ turnoff) { 412 dc->dc_blanked = turnoff; 413 /* XXX later XXX */ 414 } 415 return (0); 416 417 case WSDISPLAYIO_GVIDEO: 418 *(u_int *)data = dc->dc_blanked ? 419 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 420 return (0); 421 422 case WSDISPLAYIO_GCURPOS: 423 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 424 return (0); 425 426 case WSDISPLAYIO_SCURPOS: 427 set_curpos(sc, (struct wsdisplay_curpos *)data); 428 bt459_set_curpos(sc); 429 return (0); 430 431 case WSDISPLAYIO_GCURMAX: 432 ((struct wsdisplay_curpos *)data)->x = 433 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 434 return (0); 435 436 case WSDISPLAYIO_GCURSOR: 437 return get_cursor(sc, (struct wsdisplay_cursor *)data); 438 439 case WSDISPLAYIO_SCURSOR: 440 return set_cursor(sc, (struct wsdisplay_cursor *)data); 441 } 442 return ENOTTY; 443} 444 445paddr_t 446cfbmmap(v, offset, prot) 447 void *v; 448 off_t offset; 449 int prot; 450{ 451 struct cfb_softc *sc = v; 452 453 if (offset >= CX_FB_SIZE || offset < 0) 454 return (-1); 455 return machine_btop(sc->sc_dc->dc_paddr + offset); 456} 457 458static int 459cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 460 void *v; 461 const struct wsscreen_descr *type; 462 void **cookiep; 463 int *curxp, *curyp; 464 long *attrp; 465{ 466 struct cfb_softc *sc = v; 467 long defattr; 468 469 if (sc->nscreens > 0) 470 return (ENOMEM); 471 472 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */ 473 *curxp = 0; 474 *curyp = 0; 475 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr); 476 *attrp = defattr; 477 sc->nscreens++; 478 return (0); 479} 480 481static void 482cfb_free_screen(v, cookie) 483 void *v; 484 void *cookie; 485{ 486 struct cfb_softc *sc = v; 487 488 if (sc->sc_dc == &cfb_console_dc) 489 panic("cfb_free_screen: console"); 490 491 sc->nscreens--; 492} 493 494static int 495cfb_show_screen(v, cookie, waitok, cb, cbarg) 496 void *v; 497 void *cookie; 498 int waitok; 499 void (*cb) __P((void *, int, int)); 500 void *cbarg; 501{ 502 503 return (0); 504} 505 506/* EXPORT */ int 507cfb_cnattach(addr) 508 tc_addr_t addr; 509{ 510 struct fb_devconfig *dcp = &cfb_console_dc; 511 long defattr; 512 513 cfb_getdevconfig(addr, dcp); 514 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr); 515 wsdisplay_cnattach(&cfb_stdscreen, &dcp->rinfo, 0, 0, defattr); 516 cfb_consaddr = addr; 517 return(0); 518} 519 520static int 521cfbintr(arg) 522 void *arg; 523{ 524 struct cfb_softc *sc = arg; 525 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 526 struct bt459reg *vdac; 527 int v; 528 529 *(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0; 530 if (sc->sc_changed == 0) 531 return (1); 532 533 vdac = (void *)(cfbbase + CX_BT459_OFFSET); 534 v = sc->sc_changed; 535 sc->sc_changed = 0; 536 if (v & DATA_ENB_CHANGED) { 537 SELECT(vdac, BT459_IREG_CCR); 538 REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00; 539 } 540 if (v & DATA_CURCMAP_CHANGED) { 541 u_int8_t *cp = sc->sc_cursor.cc_color; 542 543 SELECT(vdac, BT459_IREG_CCOLOR_2); 544 REG(vdac, bt_reg) = cp[1]; tc_wmb(); 545 REG(vdac, bt_reg) = cp[3]; tc_wmb(); 546 REG(vdac, bt_reg) = cp[5]; tc_wmb(); 547 548 REG(vdac, bt_reg) = cp[0]; tc_wmb(); 549 REG(vdac, bt_reg) = cp[2]; tc_wmb(); 550 REG(vdac, bt_reg) = cp[4]; tc_wmb(); 551 } 552 if (v & DATA_CURSHAPE_CHANGED) { 553 u_int8_t *ip, *mp, img, msk; 554 u_int8_t u; 555 int bcnt; 556 557 ip = (u_int8_t *)sc->sc_cursor.cc_image; 558 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE); 559 560 bcnt = 0; 561 SELECT(vdac, BT459_IREG_CRAM_BASE+0); 562 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 563 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 564 /* pad right half 32 pixel when smaller than 33 */ 565 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 566 REG(vdac, bt_reg) = 0; tc_wmb(); 567 REG(vdac, bt_reg) = 0; tc_wmb(); 568 } 569 else { 570 img = *ip++; 571 msk = *mp++; 572 img &= msk; /* cookie off image */ 573 u = (msk & 0x0f) << 4 | (img & 0x0f); 574 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 575 u = (msk & 0xf0) | (img & 0xf0) >> 4; 576 REG(vdac, bt_reg) = shuffle[u]; tc_wmb(); 577 } 578 bcnt += 2; 579 } 580 /* pad unoccupied scan lines */ 581 while (bcnt < CURSOR_MAX_SIZE * 16) { 582 REG(vdac, bt_reg) = 0; tc_wmb(); 583 REG(vdac, bt_reg) = 0; tc_wmb(); 584 bcnt += 2; 585 } 586 } 587 if (v & DATA_CMAP_CHANGED) { 588 struct hwcmap256 *cm = &sc->sc_cmap; 589 int index; 590 591 SELECT(vdac, 0); 592 for (index = 0; index < CMAP_SIZE; index++) { 593 REG(vdac, bt_cmap) = cm->r[index]; tc_wmb(); 594 REG(vdac, bt_cmap) = cm->g[index]; tc_wmb(); 595 REG(vdac, bt_cmap) = cm->b[index]; tc_wmb(); 596 } 597 } 598 return (1); 599} 600 601static void 602cfbinit(dc) 603 struct fb_devconfig *dc; 604{ 605 caddr_t cfbbase = (caddr_t)dc->dc_vaddr; 606 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET); 607 const u_int8_t *p; 608 int i; 609 610 SELECT(vdac, BT459_IREG_COMMAND_0); 611 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb(); 612 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb(); 613 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb(); 614 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb(); 615 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb(); 616 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb(); 617 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb(); 618 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb(); 619 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb(); 620 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb(); 621 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb(); 622 623 SELECT(vdac, BT459_IREG_CCR); 624 REG(vdac, bt_reg) = 0x0; tc_wmb(); 625 REG(vdac, bt_reg) = 0x0; tc_wmb(); 626 REG(vdac, bt_reg) = 0x0; tc_wmb(); 627 REG(vdac, bt_reg) = 0x0; tc_wmb(); 628 REG(vdac, bt_reg) = 0x0; tc_wmb(); 629 REG(vdac, bt_reg) = 0x0; tc_wmb(); 630 REG(vdac, bt_reg) = 0x0; tc_wmb(); 631 REG(vdac, bt_reg) = 0x0; tc_wmb(); 632 REG(vdac, bt_reg) = 0x0; tc_wmb(); 633 REG(vdac, bt_reg) = 0x0; tc_wmb(); 634 REG(vdac, bt_reg) = 0x0; tc_wmb(); 635 REG(vdac, bt_reg) = 0x0; tc_wmb(); 636 REG(vdac, bt_reg) = 0x0; tc_wmb(); 637 638 /* build sane colormap */ 639 SELECT(vdac, 0); 640 p = rasops_cmap; 641 for (i = 0; i < CMAP_SIZE; i++) { 642 REG(vdac, bt_cmap) = p[0]; tc_wmb(); 643 REG(vdac, bt_cmap) = p[1]; tc_wmb(); 644 REG(vdac, bt_cmap) = p[2]; tc_wmb(); 645 } 646 647 /* clear out cursor image */ 648 SELECT(vdac, BT459_IREG_CRAM_BASE); 649 for (i = 0; i < 1024; i++) 650 REG(vdac, bt_reg) = 0xff; tc_wmb(); 651 652 /* 653 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for 654 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for 655 * image color. CCOLOR_1 will be never used. 656 */ 657 SELECT(vdac, BT459_IREG_CCOLOR_1); 658 REG(vdac, bt_reg) = 0xff; tc_wmb(); 659 REG(vdac, bt_reg) = 0xff; tc_wmb(); 660 REG(vdac, bt_reg) = 0xff; tc_wmb(); 661 662 REG(vdac, bt_reg) = 0; tc_wmb(); 663 REG(vdac, bt_reg) = 0; tc_wmb(); 664 REG(vdac, bt_reg) = 0; tc_wmb(); 665 666 REG(vdac, bt_reg) = 0xff; tc_wmb(); 667 REG(vdac, bt_reg) = 0xff; tc_wmb(); 668 REG(vdac, bt_reg) = 0xff; tc_wmb(); 669} 670 671static int 672get_cmap(sc, p) 673 struct cfb_softc *sc; 674 struct wsdisplay_cmap *p; 675{ 676 u_int index = p->index, count = p->count; 677 678 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 679 return (EINVAL); 680 681 if (!uvm_useracc(p->red, count, B_WRITE) || 682 !uvm_useracc(p->green, count, B_WRITE) || 683 !uvm_useracc(p->blue, count, B_WRITE)) 684 return (EFAULT); 685 686 copyout(&sc->sc_cmap.r[index], p->red, count); 687 copyout(&sc->sc_cmap.g[index], p->green, count); 688 copyout(&sc->sc_cmap.b[index], p->blue, count); 689 690 return (0); 691} 692 693static int 694set_cmap(sc, p) 695 struct cfb_softc *sc; 696 struct wsdisplay_cmap *p; 697{ 698 u_int index = p->index, count = p->count; 699 700 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 701 return (EINVAL); 702 703 if (!uvm_useracc(p->red, count, B_READ) || 704 !uvm_useracc(p->green, count, B_READ) || 705 !uvm_useracc(p->blue, count, B_READ)) 706 return (EFAULT); 707 708 copyin(p->red, &sc->sc_cmap.r[index], count); 709 copyin(p->green, &sc->sc_cmap.g[index], count); 710 copyin(p->blue, &sc->sc_cmap.b[index], count); 711 712 sc->sc_changed |= DATA_CMAP_CHANGED; 713 714 return (0); 715} 716 717static int 718set_cursor(sc, p) 719 struct cfb_softc *sc; 720 struct wsdisplay_cursor *p; 721{ 722#define cc (&sc->sc_cursor) 723 int v, index, count, icount; 724 725 v = p->which; 726 if (v & WSDISPLAY_CURSOR_DOCMAP) { 727 index = p->cmap.index; 728 count = p->cmap.count; 729 if (index >= 2 || (index + count) > 2) 730 return (EINVAL); 731 if (!uvm_useracc(p->cmap.red, count, B_READ) || 732 !uvm_useracc(p->cmap.green, count, B_READ) || 733 !uvm_useracc(p->cmap.blue, count, B_READ)) 734 return (EFAULT); 735 } 736 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 737 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 738 return (EINVAL); 739 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 740 if (!uvm_useracc(p->image, icount, B_READ) || 741 !uvm_useracc(p->mask, icount, B_READ)) 742 return (EFAULT); 743 } 744 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) { 745 if (v & WSDISPLAY_CURSOR_DOCUR) 746 cc->cc_hot = p->hot; 747 if (v & WSDISPLAY_CURSOR_DOPOS) 748 set_curpos(sc, &p->pos); 749 bt459_set_curpos(sc); 750 } 751 752 sc->sc_changed = 0; 753 if (v & WSDISPLAY_CURSOR_DOCUR) { 754 sc->sc_curenb = p->enable; 755 sc->sc_changed |= DATA_ENB_CHANGED; 756 } 757 if (v & WSDISPLAY_CURSOR_DOCMAP) { 758 copyin(p->cmap.red, &cc->cc_color[index], count); 759 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 760 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 761 sc->sc_changed |= DATA_CURCMAP_CHANGED; 762 } 763 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 764 cc->cc_size = p->size; 765 memset(cc->cc_image, 0, sizeof cc->cc_image); 766 copyin(p->image, cc->cc_image, icount); 767 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount); 768 sc->sc_changed |= DATA_CURSHAPE_CHANGED; 769 } 770 771 return (0); 772#undef cc 773} 774 775static int 776get_cursor(sc, p) 777 struct cfb_softc *sc; 778 struct wsdisplay_cursor *p; 779{ 780 return (ENOTTY); /* XXX */ 781} 782 783static void 784set_curpos(sc, curpos) 785 struct cfb_softc *sc; 786 struct wsdisplay_curpos *curpos; 787{ 788 struct fb_devconfig *dc = sc->sc_dc; 789 int x = curpos->x, y = curpos->y; 790 791 if (y < 0) 792 y = 0; 793 else if (y > dc->dc_ht) 794 y = dc->dc_ht; 795 if (x < 0) 796 x = 0; 797 else if (x > dc->dc_wid) 798 x = dc->dc_wid; 799 sc->sc_cursor.cc_pos.x = x; 800 sc->sc_cursor.cc_pos.y = y; 801} 802 803void 804bt459_set_curpos(sc) 805 struct cfb_softc *sc; 806{ 807 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr; 808 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET); 809 int x, y, s; 810 811 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 812 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 813 814 x += sc->sc_cursor.cc_magic.x; 815 y += sc->sc_cursor.cc_magic.y; 816 817 s = spltty(); 818 819 SELECT(vdac, BT459_IREG_CURSOR_X_LOW); 820 REG(vdac, bt_reg) = x; tc_wmb(); 821 REG(vdac, bt_reg) = x >> 8; tc_wmb(); 822 REG(vdac, bt_reg) = y; tc_wmb(); 823 REG(vdac, bt_reg) = y >> 8; tc_wmb(); 824 825 splx(s); 826} 827