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