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