1 /* $NetBSD: xcfb.c,v 1.32 2002/10/02 16:53:09 thorpej 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> 34 __KERNEL_RCSID(0, "$NetBSD: xcfb.c,v 1.32 2002/10/02 16:53:09 thorpej Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 #include <sys/buf.h> 42 #include <sys/ioctl.h> 43 44 #include <machine/bus.h> 45 #include <machine/intr.h> 46 47 #include <dev/wscons/wsconsio.h> 48 #include <dev/wscons/wsdisplayvar.h> 49 50 #include <dev/rasops/rasops.h> 51 #include <dev/wsfont/wsfont.h> 52 53 #include <dev/tc/tcvar.h> 54 #include <dev/tc/ioasicreg.h> 55 #include <dev/ic/ims332reg.h> 56 #include <pmax/pmax/maxine.h> 57 58 #include <uvm/uvm_extern.h> 59 60 struct hwcmap256 { 61 #define CMAP_SIZE 256 /* 256 R/G/B entries */ 62 u_int8_t r[CMAP_SIZE]; 63 u_int8_t g[CMAP_SIZE]; 64 u_int8_t b[CMAP_SIZE]; 65 }; 66 67 struct hwcursor64 { 68 struct wsdisplay_curpos cc_pos; 69 struct wsdisplay_curpos cc_hot; 70 struct wsdisplay_curpos cc_size; 71 struct wsdisplay_curpos cc_magic; /* not used by PMAG-DV */ 72 #define CURSOR_MAX_SIZE 64 73 u_int8_t cc_color[6]; 74 u_int64_t cc_image[64 + 64]; 75 }; 76 77 #define XCFB_FB_BASE (XINE_PHYS_CFB_START + 0x2000000) 78 #define XCFB_FB_SIZE 0x100000 79 80 #define IMS332_HIGH (IOASIC_SLOT_5_START) 81 #define IMS332_RLOW (IOASIC_SLOT_7_START) 82 #define IMS332_WLOW (IOASIC_SLOT_7_START + 0x20000) 83 84 struct xcfb_softc { 85 struct device sc_dev; 86 vaddr_t sc_vaddr; 87 size_t sc_size; 88 struct rasops_info *sc_ri; 89 struct hwcmap256 sc_cmap; /* software copy of colormap */ 90 struct hwcursor64 sc_cursor; /* software copy of cursor */ 91 int sc_blanked; 92 /* XXX MAXINE can take PMAG-DV vertical retrace interrupt XXX */ 93 int nscreens; 94 /* cursor coordinate is located at upper-left corner */ 95 int sc_csr; /* software copy of IMS332 CSR A */ 96 }; 97 98 static int xcfbmatch __P((struct device *, struct cfdata *, void *)); 99 static void xcfbattach __P((struct device *, struct device *, void *)); 100 101 CFATTACH_DECL(xcfb, sizeof(struct xcfb_softc), 102 xcfbmatch, xcfbattach, NULL, NULL); 103 104 static tc_addr_t xcfb_consaddr; 105 static struct rasops_info xcfb_console_ri; 106 static void xcfb_common_init __P((struct rasops_info *)); 107 static void xcfbhwinit __P((caddr_t)); 108 int xcfb_cnattach __P((void)); 109 110 struct wsscreen_descr xcfb_stdscreen = { 111 "std", 0, 0, 112 0, /* textops */ 113 0, 0, 114 WSSCREEN_REVERSE 115 }; 116 117 static const struct wsscreen_descr *_xcfb_scrlist[] = { 118 &xcfb_stdscreen, 119 }; 120 121 static const struct wsscreen_list xcfb_screenlist = { 122 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist 123 }; 124 125 static int xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 126 static paddr_t xcfbmmap __P((void *, off_t, int)); 127 128 static int xcfb_alloc_screen __P((void *, const struct wsscreen_descr *, 129 void **, int *, int *, long *)); 130 static void xcfb_free_screen __P((void *, void *)); 131 static int xcfb_show_screen __P((void *, void *, int, 132 void (*) (void *, int, int), void *)); 133 134 static const struct wsdisplay_accessops xcfb_accessops = { 135 xcfbioctl, 136 xcfbmmap, 137 xcfb_alloc_screen, 138 xcfb_free_screen, 139 xcfb_show_screen, 140 0 /* load_font */ 141 }; 142 143 static int xcfbintr __P((void *)); 144 static void xcfb_screenblank __P((struct xcfb_softc *)); 145 static int set_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *)); 146 static int get_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *)); 147 static int set_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *)); 148 static int get_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *)); 149 static void set_curpos __P((struct xcfb_softc *, struct wsdisplay_curpos *)); 150 static void ims332_loadcmap __P((struct hwcmap256 *)); 151 static void ims332_set_curpos __P((struct xcfb_softc *)); 152 static void ims332_load_curcmap __P((struct xcfb_softc *)); 153 static void ims332_load_curshape __P((struct xcfb_softc *)); 154 static void ims332_write_reg __P((int, u_int32_t)); 155 #if 0 156 static u_int32_t ims332_read_reg __P((int)); 157 #endif 158 159 extern long ioasic_base; /* XXX */ 160 161 /* 162 * Compose 2 bit/pixel cursor image. 163 * M M M M I I I I M I M I M I M I 164 * [ before ] [ after ] 165 * 3 2 1 0 3 2 1 0 3 3 2 2 1 1 0 0 166 * 7 6 5 4 7 6 5 4 7 7 6 6 5 5 4 4 167 */ 168 static const u_int8_t shuffle[256] = { 169 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15, 170 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55, 171 0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17, 172 0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57, 173 0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d, 174 0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d, 175 0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f, 176 0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f, 177 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35, 178 0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75, 179 0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37, 180 0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77, 181 0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d, 182 0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d, 183 0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f, 184 0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f, 185 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95, 186 0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5, 187 0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97, 188 0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7, 189 0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d, 190 0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd, 191 0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f, 192 0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf, 193 0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5, 194 0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5, 195 0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7, 196 0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7, 197 0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd, 198 0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd, 199 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, 200 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff, 201 }; 202 203 static int 204 xcfbmatch(parent, match, aux) 205 struct device *parent; 206 struct cfdata *match; 207 void *aux; 208 { 209 struct tc_attach_args *ta = aux; 210 211 if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0) 212 return (0); 213 214 return (1); 215 } 216 217 static void 218 xcfbattach(parent, self, aux) 219 struct device *parent, *self; 220 void *aux; 221 { 222 struct xcfb_softc *sc = (struct xcfb_softc *)self; 223 struct tc_attach_args *ta = aux; 224 struct rasops_info *ri; 225 struct wsemuldisplaydev_attach_args waa; 226 struct hwcmap256 *cm; 227 const u_int8_t *p; 228 int console, index; 229 230 console = (ta->ta_addr == xcfb_consaddr); 231 if (console) { 232 sc->sc_ri = ri = &xcfb_console_ri; 233 sc->nscreens = 1; 234 } 235 else { 236 MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info), 237 M_DEVBUF, M_NOWAIT); 238 if (ri == NULL) { 239 printf(": can't alloc memory\n"); 240 return; 241 } 242 memset(ri, 0, sizeof(struct rasops_info)); 243 244 ri->ri_hw = (void *)ioasic_base; 245 xcfb_common_init(ri); 246 sc->sc_ri = ri; 247 } 248 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 249 250 cm = &sc->sc_cmap; 251 p = rasops_cmap; 252 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 253 cm->r[index] = p[0]; 254 cm->g[index] = p[1]; 255 cm->b[index] = p[2]; 256 } 257 258 sc->sc_vaddr = ta->ta_addr; 259 sc->sc_blanked = 0; 260 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE; 261 262 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc); 263 264 waa.console = console; 265 waa.scrdata = &xcfb_screenlist; 266 waa.accessops = &xcfb_accessops; 267 waa.accesscookie = sc; 268 269 config_found(self, &waa, wsemuldisplaydevprint); 270 } 271 272 static void 273 xcfb_common_init(ri) 274 struct rasops_info *ri; 275 { 276 int cookie; 277 278 /* initialize colormap and cursor hardware */ 279 xcfbhwinit((caddr_t)ri->ri_hw); 280 281 ri->ri_flg = RI_CENTER; 282 ri->ri_depth = 8; 283 ri->ri_width = 1024; 284 ri->ri_height = 768; 285 ri->ri_stride = 1024; 286 ri->ri_bits = (caddr_t)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE); 287 288 /* clear the screen */ 289 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 290 291 wsfont_init(); 292 /* prefer 12 pixel wide font */ 293 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R, 294 WSDISPLAY_FONTORDER_L2R); 295 if (cookie <= 0) 296 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R, 297 WSDISPLAY_FONTORDER_L2R); 298 if (cookie <= 0) { 299 printf("xcfb: font table is empty\n"); 300 return; 301 } 302 303 if (wsfont_lock(cookie, &ri->ri_font)) { 304 printf("xcfb: couldn't lock font\n"); 305 return; 306 } 307 ri->ri_wsfcookie = cookie; 308 309 rasops_init(ri, 34, 80); 310 311 /* XXX shouldn't be global */ 312 xcfb_stdscreen.nrows = ri->ri_rows; 313 xcfb_stdscreen.ncols = ri->ri_cols; 314 xcfb_stdscreen.textops = &ri->ri_ops; 315 xcfb_stdscreen.capabilities = ri->ri_caps; 316 } 317 318 int 319 xcfb_cnattach() 320 { 321 struct rasops_info *ri; 322 long defattr; 323 324 ri = &xcfb_console_ri; 325 ri->ri_hw = (void *)ioasic_base; 326 xcfb_common_init(ri); 327 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 328 wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr); 329 xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START); 330 return (0); 331 } 332 333 static void 334 xcfbhwinit(base) 335 caddr_t base; 336 { 337 u_int32_t *csr, i; 338 const u_int8_t *p; 339 340 csr = (u_int32_t *)(base + IOASIC_CSR); 341 i = *csr; 342 i &= ~XINE_CSR_VDAC_ENABLE; 343 *csr = i; 344 DELAY(50); 345 i |= XINE_CSR_VDAC_ENABLE; 346 *csr = i; 347 DELAY(50); 348 ims332_write_reg(IMS332_REG_BOOT, 0x2c); 349 ims332_write_reg(IMS332_REG_CSR_A, 350 IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR); 351 ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10); 352 ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21); 353 ims332_write_reg(IMS332_REG_DISPLAY, 0x100); 354 ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d); 355 ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f); 356 ims332_write_reg(IMS332_REG_LINE_TIME, 0x146); 357 ims332_write_reg(IMS332_REG_V_SYNC, 0x0c); 358 ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02); 359 ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02); 360 ims332_write_reg(IMS332_REG_V_BLANK, 0x2a); 361 ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600); 362 ims332_write_reg(IMS332_REG_LINE_START, 0x10); 363 ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a); 364 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff); 365 ims332_write_reg(IMS332_REG_CSR_A, 366 IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE); 367 368 /* build sane colormap */ 369 p = rasops_cmap; 370 for (i = 0; i < CMAP_SIZE; i++, p += 3) { 371 u_int32_t bgr; 372 373 bgr = p[2] << 16 | p[1] << 8 | p[0]; 374 ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr); 375 } 376 377 /* clear out cursor image */ 378 for (i = 0; i < 512; i++) 379 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0); 380 381 /* 382 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for 383 * cursor image. LUT_1 for mask color, while LUT_2 for 384 * image color. LUT_0 will be never used. 385 */ 386 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0); 387 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff); 388 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff); 389 } 390 391 static int 392 xcfbioctl(v, cmd, data, flag, p) 393 void *v; 394 u_long cmd; 395 caddr_t data; 396 int flag; 397 struct proc *p; 398 { 399 struct xcfb_softc *sc = v; 400 struct rasops_info *ri = sc->sc_ri; 401 int turnoff, error; 402 403 switch (cmd) { 404 case WSDISPLAYIO_GTYPE: 405 *(u_int *)data = WSDISPLAY_TYPE_XCFB; 406 return (0); 407 408 case WSDISPLAYIO_GINFO: 409 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 410 wsd_fbip->height = ri->ri_height; 411 wsd_fbip->width = ri->ri_width; 412 wsd_fbip->depth = ri->ri_depth; 413 wsd_fbip->cmsize = CMAP_SIZE; 414 #undef fbt 415 return (0); 416 417 case WSDISPLAYIO_GETCMAP: 418 return get_cmap(sc, (struct wsdisplay_cmap *)data); 419 420 case WSDISPLAYIO_PUTCMAP: 421 error = set_cmap(sc, (struct wsdisplay_cmap *)data); 422 if (error == 0) 423 ims332_loadcmap(&sc->sc_cmap); 424 return (error); 425 426 case WSDISPLAYIO_SVIDEO: 427 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 428 if ((sc->sc_blanked == 0) ^ turnoff) { 429 sc->sc_blanked = turnoff; 430 xcfb_screenblank(sc); 431 } 432 return (0); 433 434 case WSDISPLAYIO_GVIDEO: 435 *(u_int *)data = sc->sc_blanked ? 436 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 437 return (0); 438 439 case WSDISPLAYIO_GCURPOS: 440 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 441 return (0); 442 443 case WSDISPLAYIO_SCURPOS: 444 set_curpos(sc, (struct wsdisplay_curpos *)data); 445 ims332_set_curpos(sc); 446 return (0); 447 448 case WSDISPLAYIO_GCURMAX: 449 ((struct wsdisplay_curpos *)data)->x = 450 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 451 return (0); 452 453 case WSDISPLAYIO_GCURSOR: 454 return get_cursor(sc, (struct wsdisplay_cursor *)data); 455 456 case WSDISPLAYIO_SCURSOR: 457 return set_cursor(sc, (struct wsdisplay_cursor *)data); 458 } 459 return (EPASSTHROUGH); 460 } 461 462 static paddr_t 463 xcfbmmap(v, offset, prot) 464 void *v; 465 off_t offset; 466 int prot; 467 { 468 469 if (offset >= XCFB_FB_SIZE || offset < 0) 470 return (-1); 471 return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset)); 472 } 473 474 static int 475 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 476 void *v; 477 const struct wsscreen_descr *type; 478 void **cookiep; 479 int *curxp, *curyp; 480 long *attrp; 481 { 482 struct xcfb_softc *sc = v; 483 struct rasops_info *ri = sc->sc_ri; 484 long defattr; 485 486 if (sc->nscreens > 0) 487 return (ENOMEM); 488 489 *cookiep = ri; /* one and only for now */ 490 *curxp = 0; 491 *curyp = 0; 492 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 493 *attrp = defattr; 494 sc->nscreens++; 495 return (0); 496 } 497 498 static void 499 xcfb_free_screen(v, cookie) 500 void *v; 501 void *cookie; 502 { 503 struct xcfb_softc *sc = v; 504 505 if (sc->sc_ri == &xcfb_console_ri) 506 panic("xcfb_free_screen: console"); 507 508 sc->nscreens--; 509 } 510 511 static int 512 xcfb_show_screen(v, cookie, waitok, cb, cbarg) 513 void *v; 514 void *cookie; 515 int waitok; 516 void (*cb) __P((void *, int, int)); 517 void *cbarg; 518 { 519 520 return (0); 521 } 522 523 static int 524 xcfbintr(v) 525 void *v; 526 { 527 struct xcfb_softc *sc = v; 528 u_int32_t *intr, i; 529 530 intr = (u_int32_t *)((caddr_t)sc->sc_ri->ri_hw + IOASIC_INTR); 531 i = *intr; 532 i &= ~XINE_INTR_VINT; 533 *intr = i; 534 return (1); 535 } 536 537 static void 538 xcfb_screenblank(sc) 539 struct xcfb_softc *sc; 540 { 541 if (sc->sc_blanked) 542 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK; 543 else 544 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK; 545 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 546 } 547 548 static int 549 get_cmap(sc, p) 550 struct xcfb_softc *sc; 551 struct wsdisplay_cmap *p; 552 { 553 u_int index = p->index, count = p->count; 554 555 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 556 return (EINVAL); 557 558 if (!uvm_useracc(p->red, count, B_WRITE) || 559 !uvm_useracc(p->green, count, B_WRITE) || 560 !uvm_useracc(p->blue, count, B_WRITE)) 561 return (EFAULT); 562 563 copyout(&sc->sc_cmap.r[index], p->red, count); 564 copyout(&sc->sc_cmap.g[index], p->green, count); 565 copyout(&sc->sc_cmap.b[index], p->blue, count); 566 567 return (0); 568 } 569 570 static int 571 set_cmap(sc, p) 572 struct xcfb_softc *sc; 573 struct wsdisplay_cmap *p; 574 { 575 u_int index = p->index, count = p->count; 576 577 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 578 return (EINVAL); 579 580 if (!uvm_useracc(p->red, count, B_READ) || 581 !uvm_useracc(p->green, count, B_READ) || 582 !uvm_useracc(p->blue, count, B_READ)) 583 return (EFAULT); 584 585 copyin(p->red, &sc->sc_cmap.r[index], count); 586 copyin(p->green, &sc->sc_cmap.g[index], count); 587 copyin(p->blue, &sc->sc_cmap.b[index], count); 588 589 return (0); 590 } 591 592 static int 593 set_cursor(sc, p) 594 struct xcfb_softc *sc; 595 struct wsdisplay_cursor *p; 596 { 597 #define cc (&sc->sc_cursor) 598 u_int v, index, count; 599 600 v = p->which; 601 if (v & WSDISPLAY_CURSOR_DOCMAP) { 602 index = p->cmap.index; 603 count = p->cmap.count; 604 605 if (index >= 2 || index + count > 2) 606 return (EINVAL); 607 if (!uvm_useracc(p->cmap.red, count, B_READ) || 608 !uvm_useracc(p->cmap.green, count, B_READ) || 609 !uvm_useracc(p->cmap.blue, count, B_READ)) 610 return (EFAULT); 611 612 copyin(p->cmap.red, &cc->cc_color[index], count); 613 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 614 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 615 ims332_load_curcmap(sc); 616 } 617 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 618 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 619 return (EINVAL); 620 count = ((p->size.x < 33) ? 4 : 8) * p->size.y; 621 if (!uvm_useracc(p->image, count, B_READ) || 622 !uvm_useracc(p->mask, count, B_READ)) 623 return (EFAULT); 624 cc->cc_size = p->size; 625 memset(cc->cc_image, 0, sizeof cc->cc_image); 626 copyin(p->image, cc->cc_image, count); 627 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count); 628 ims332_load_curshape(sc); 629 } 630 if (v & WSDISPLAY_CURSOR_DOCUR) { 631 cc->cc_hot = p->hot; 632 if (p->enable) 633 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR; 634 else 635 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR; 636 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 637 } 638 if (v & WSDISPLAY_CURSOR_DOPOS) { 639 set_curpos(sc, &p->pos); 640 ims332_set_curpos(sc); 641 } 642 643 return (0); 644 #undef cc 645 } 646 647 static int 648 get_cursor(sc, p) 649 struct xcfb_softc *sc; 650 struct wsdisplay_cursor *p; 651 { 652 return (EPASSTHROUGH); /* XXX */ 653 } 654 655 static void 656 set_curpos(sc, curpos) 657 struct xcfb_softc *sc; 658 struct wsdisplay_curpos *curpos; 659 { 660 struct rasops_info *ri = sc->sc_ri; 661 int x = curpos->x, y = curpos->y; 662 663 if (y < 0) 664 y = 0; 665 else if (y > ri->ri_height) 666 y = ri->ri_height; 667 if (x < 0) 668 x = 0; 669 else if (x > ri->ri_width) 670 x = ri->ri_width; 671 sc->sc_cursor.cc_pos.x = x; 672 sc->sc_cursor.cc_pos.y = y; 673 } 674 675 static void 676 ims332_loadcmap(cm) 677 struct hwcmap256 *cm; 678 { 679 int i; 680 u_int32_t rgb; 681 682 for (i = 0; i < CMAP_SIZE; i++) { 683 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i]; 684 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb); 685 } 686 } 687 688 static void 689 ims332_set_curpos(sc) 690 struct xcfb_softc *sc; 691 { 692 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos; 693 u_int32_t pos; 694 int s; 695 696 s = spltty(); 697 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff); 698 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos); 699 splx(s); 700 } 701 702 static void 703 ims332_load_curcmap(sc) 704 struct xcfb_softc *sc; 705 { 706 u_int8_t *cp = sc->sc_cursor.cc_color; 707 u_int32_t rgb; 708 709 /* cursor background */ 710 rgb = cp[5] << 16 | cp[3] << 8 | cp[1]; 711 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb); 712 713 /* cursor foreground */ 714 rgb = cp[4] << 16 | cp[2] << 8 | cp[0]; 715 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb); 716 } 717 718 static void 719 ims332_load_curshape(sc) 720 struct xcfb_softc *sc; 721 { 722 unsigned i, img, msk, bits; 723 u_int8_t u, *ip, *mp; 724 725 ip = (u_int8_t *)sc->sc_cursor.cc_image; 726 mp = (u_int8_t *)(sc->sc_cursor.cc_image+CURSOR_MAX_SIZE); 727 728 i = 0; 729 /* 64 pixel scan line is consisted with 8 halfword cursor ram */ 730 while (i < sc->sc_cursor.cc_size.y * 8) { 731 /* pad right half 32 pixel when smaller than 33 */ 732 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33) 733 bits = 0; 734 else { 735 img = *ip++; 736 msk = *mp++; 737 img &= msk; /* cookie off image */ 738 u = (msk & 0x0f) << 4 | (img & 0x0f); 739 bits = shuffle[u]; 740 u = (msk & 0xf0) | (img & 0xf0) >> 4; 741 bits = (shuffle[u] << 8) | bits; 742 } 743 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits); 744 i += 1; 745 } 746 /* pad unoccupied scan lines */ 747 while (i < CURSOR_MAX_SIZE * 8) { 748 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0); 749 i += 1; 750 } 751 } 752 753 static void 754 ims332_write_reg(regno, val) 755 int regno; 756 u_int32_t val; 757 { 758 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH); 759 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4); 760 761 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8; 762 *(volatile u_int16_t *)low16 = val; 763 } 764 765 #if 0 766 static u_int32_t 767 ims332_read_reg(regno) 768 int regno; 769 { 770 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH); 771 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4); 772 u_int v0, v1; 773 774 v1 = *(volatile u_int16_t *)high8; 775 v0 = *(volatile u_int16_t *)low16; 776 return (v1 & 0xff00) << 8 | v0; 777 } 778 #endif 779