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