Home | History | Annotate | Line # | Download | only in ibus
pm.c revision 1.1.2.16
      1 /* $NetBSD: pm.c,v 1.1.2.16 2000/02/03 09:46: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, "$Id: pm.c,v 1.1.2.16 2000/02/03 09:46:49 nisimura Exp $");
     36 
     37 #include <sys/param.h>
     38 #include <sys/systm.h>
     39 #include <sys/device.h>
     40 #include <sys/kernel.h>
     41 #include <sys/malloc.h>
     42 #include <sys/buf.h>
     43 #include <sys/ioctl.h>
     44 #include <vm/vm.h>
     45 #include <uvm/uvm_extern.h>
     46 
     47 #include <dev/rcons/raster.h>
     48 #include <dev/wscons/wsconsio.h>
     49 #include <dev/wscons/wscons_raster.h>
     50 #include <dev/wscons/wsdisplayvar.h>
     51 
     52 #include <machine/cpu.h>
     53 #include <machine/bus.h>
     54 #include <pmax/ibus/ibusvar.h>
     55 
     56 extern void kn01_wbflush __P((void));
     57 
     58 struct pccreg {
     59 #define	_HALF_(xxx)	u_int16_t xxx; unsigned : 16
     60 	_HALF_(pcc_cmdr);	/* cursor command register */
     61 	_HALF_(pcc_xpos);	/* cursor X position */
     62 	_HALF_(pcc_ypos);	/* cursor Y position */
     63 	_HALF_(pcc_xmin1);	/* region 1 top edge */
     64 	_HALF_(pcc_xmax1);	/* region 1 bottom edge */
     65 	_HALF_(pcc_ymin1);	/* region 1 top edge */
     66 	_HALF_(pcc_ymax1);	/* region 1 bottom edge */
     67 	unsigned : 32;		/* unused */
     68 	unsigned : 32;		/* unused */
     69 	unsigned : 32;		/* unused */
     70 	unsigned : 32;		/* unused */
     71 	_HALF_(pcc_xmin2);	/* region 2 top edge */
     72 	_HALF_(pcc_xmax2);	/* region 2 bottom edge */
     73 	_HALF_(pcc_ymin2);	/* region 2 top edge */
     74 	_HALF_(pcc_ymax2);	/* region 2 bottom edge */
     75 	_HALF_(pcc_memory);	/* cursor sprite pattern load */
     76 #undef	_HALF_
     77 };
     78 
     79 #define	PCC_ENPA	0000001
     80 #define	PCC_FOPA	0000002
     81 #define	PCC_ENPB	0000004
     82 #define	PCC_FOPB	0000010
     83 #define	PCC_XHAIR	0000020
     84 #define	PCC_XHCLP	0000040
     85 #define	PCC_XHCL1	0000100
     86 #define	PCC_XHWID	0000200
     87 #define	PCC_ENRG1	0000400
     88 #define	PCC_FORG1	0001000
     89 #define	PCC_ENRG2	0002000
     90 #define	PCC_FORG2	0004000
     91 #define	PCC_LODSA	0010000
     92 #define	PCC_VBHI	0020000
     93 #define	PCC_HSHI	0040000
     94 #define	PCC_TEST	0100000
     95 
     96 struct bt478reg {
     97 #define	_BYTE_(yyy)	u_int8_t yyy; unsigned : 24
     98 	_BYTE_(bt_mapWA);	/* address register (color map write) */
     99 	_BYTE_(bt_map);		/* color map */
    100 	_BYTE_(bt_mask);	/* pixel read mask */
    101 	_BYTE_(bt_mapRA);	/* address register (color map read) */
    102 	_BYTE_(bt_overWA);	/* address register (overlay map write) */
    103 	_BYTE_(bt_over);	/* overlay map */
    104 	unsigned : 32;		/* unused */
    105 	_BYTE_(bt_overRA);	/* address register (overlay map read) */
    106 #undef	_BYTE_
    107 };
    108 
    109 struct fb_devconfig {
    110 	vaddr_t dc_vaddr;		/* memory space virtual base address */
    111 	paddr_t dc_paddr;		/* memory space physical base address */
    112 	vsize_t dc_size;		/* size of slot memory */
    113 	int     dc_wid;			/* width of frame buffer */
    114 	int     dc_ht;			/* height of frame buffer */
    115 	int     dc_depth;		/* depth, bits per pixel */
    116 	int     dc_rowbytes;		/* bytes in a FB scan line */
    117 	vaddr_t	dc_videobase;		/* base of flat frame buffer */
    118 	struct raster	dc_raster;	/* raster description */
    119 	struct rcons	dc_rcons;	/* raster blitter control info */
    120 	int	    dc_blanked;		/* currently has video disabled */
    121 };
    122 
    123 struct hwcmap256 {
    124 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
    125 	u_int8_t r[CMAP_SIZE];
    126 	u_int8_t g[CMAP_SIZE];
    127 	u_int8_t b[CMAP_SIZE];
    128 };
    129 
    130 struct hwcursor16 {
    131 	struct wsdisplay_curpos cc_pos;
    132 	struct wsdisplay_curpos cc_hot;
    133 	struct wsdisplay_curpos cc_size;
    134 #define	CURSOR_MAX_SIZE	16
    135 	u_int8_t cc_color[6];
    136 	u_int32_t cc_image[16 + 16];
    137 };
    138 
    139 struct pm_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 hwcursor16 sc_cursor;	/* software copy of cursor */
    144 	/* no sc_change field because pm does not emit interrupt */
    145 	int nscreens;
    146 	short magic_x, magic_y;		/* cursor location offset */
    147 
    148 	struct pccreg *sc_pcc;
    149 	struct bt478reg *sc_vdac;
    150 	u_int16_t sc_pcccmdr;		/* software copy of PCC cmdr */
    151 };
    152 
    153 #define	PCC_MAGIC_X 212
    154 #define	PCC_MAGIC_Y 34
    155 
    156 static int  pmmatch __P((struct device *, struct cfdata *, void *));
    157 static void pmattach __P((struct device *, struct device *, void *));
    158 
    159 const struct cfattach pm_ca = {
    160 	sizeof(struct pm_softc), pmmatch, pmattach,
    161 };
    162 
    163 static u_int32_t pm_consaddr;
    164 static struct fb_devconfig pm_console_dc;
    165 static void pm_getdevconfig __P((u_int32_t, struct fb_devconfig *));
    166 static void pminit __P((struct fb_devconfig *));
    167 
    168 int  pm_cnattach __P((paddr_t));
    169 
    170 static const struct wsdisplay_emulops pm_emulops = {
    171 	rcons_cursor,
    172 	rcons_mapchar,
    173 	rcons_putchar,
    174 	rcons_copycols,
    175 	rcons_erasecols,
    176 	rcons_copyrows,
    177 	rcons_eraserows,
    178 	rcons_alloc_attr
    179 };
    180 
    181 static struct wsscreen_descr pm_stdscreen = {
    182 	"std",
    183 	0, 0,	/* will be filled in -- XXX shouldn't, it's global */
    184 	&pm_emulops,
    185 	0, 0,
    186 	WSSCREEN_REVERSE
    187 };
    188 
    189 static const struct wsscreen_descr *_pm_scrlist[] = {
    190 	&pm_stdscreen,
    191 };
    192 
    193 static const struct wsscreen_list pm_screenlist = {
    194 	sizeof(_pm_scrlist) / sizeof(struct wsscreen_descr *), _pm_scrlist
    195 };
    196 
    197 static int  pmioctl __P((void *, u_long, caddr_t, int, struct proc *));
    198 static int  pmmmap __P((void *, off_t, int));
    199 
    200 static int  pm_alloc_screen __P((void *, const struct wsscreen_descr *,
    201 				      void **, int *, int *, long *));
    202 static void pm_free_screen __P((void *, void *));
    203 static int  pm_show_screen __P((void *, void *, int,
    204 				void (*) (void *, int, int), void *));
    205 
    206 static const struct wsdisplay_accessops pm_accessops = {
    207 	pmioctl,
    208 	pmmmap,
    209 	pm_alloc_screen,
    210 	pm_free_screen,
    211 	pm_show_screen,
    212 	0 /* load_font */
    213 };
    214 
    215 
    216 static int  set_cmap __P((struct pm_softc *, struct wsdisplay_cmap *));
    217 static int  get_cmap __P((struct pm_softc *, struct wsdisplay_cmap *));
    218 static int  set_cursor __P((struct pm_softc *, struct wsdisplay_cursor *));
    219 static int  get_cursor __P((struct pm_softc *, struct wsdisplay_cursor *));
    220 static void set_curpos __P((struct pm_softc *, struct wsdisplay_curpos *));
    221 static void bt478_loadcmap __P((struct pm_softc *));
    222 static void bt478_load_curcmap __P((struct pm_softc *));
    223 static void pcc_load_curshape __P((struct pm_softc *));
    224 static void pcc_set_curpos __P((struct pm_softc *));
    225 static void pcc_show_cursor __P((struct pm_softc *, int));
    226 
    227 #define	KN01_SYS_PCC	0x11100000
    228 #define	KN01_SYS_BT478	0x11200000
    229 #define	KN01_SYS_PMASK	0x10000000
    230 #define	KN01_SYS_CSR	0x1e000000
    231 #define	KN01_CSR_MONO	    0x0800
    232 
    233 
    234 static int
    235 pmmatch(parent, match, aux)
    236 	struct device *parent;
    237 	struct cfdata *match;
    238 	void *aux;
    239 {
    240 	struct ibus_attach_args *ia = aux;
    241 
    242 	if (strcmp("pm", ia->ia_name))
    243 		return (0);
    244 	if (badaddr((char *)ia->ia_addr, 4))
    245 		return (0);
    246 	return (1);
    247 }
    248 
    249 static void
    250 pm_getdevconfig(dense_addr, dc)
    251 	u_int32_t dense_addr;
    252 	struct fb_devconfig *dc;
    253 {
    254 	struct raster *rap;
    255 	struct rcons *rcp;
    256 	u_int16_t *p = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_CSR);
    257 	int i;
    258 
    259 	dc->dc_wid = 1024;
    260 	dc->dc_ht = 864;
    261 	dc->dc_depth = (*p & KN01_CSR_MONO) ? 1 : 8;
    262 	dc->dc_rowbytes = (dc->dc_depth == 8) ? 1024 : 1024 / 8;
    263 	dc->dc_videobase = dense_addr;
    264 	dc->dc_blanked = 0;
    265 
    266 	dc->dc_vaddr = dense_addr;
    267 	dc->dc_paddr = MIPS_KSEG1_TO_PHYS(dc->dc_vaddr);
    268 	dc->dc_size = (dc->dc_depth == 8) ? 0x100000 : 0x40000;
    269 
    270 	/* initialize colormap and cursor resource */
    271 	pminit(dc);
    272 
    273 	/* clear the screen */
    274 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    275 		*(u_int32_t *)(dc->dc_videobase + i) = 0;
    276 
    277 	/* initialize the raster */
    278 	rap = &dc->dc_raster;
    279 	rap->width = dc->dc_wid;
    280 	rap->height = dc->dc_ht;
    281 	rap->depth = dc->dc_depth;
    282 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
    283 	rap->pixels = (u_int32_t *)dc->dc_videobase;
    284 
    285 	/* initialize the raster console blitter */
    286 	rcp = &dc->dc_rcons;
    287 	rcp->rc_sp = rap;
    288 	rcp->rc_crow = rcp->rc_ccol = -1;
    289 	rcp->rc_crowp = &rcp->rc_crow;
    290 	rcp->rc_ccolp = &rcp->rc_ccol;
    291 	rcons_init(rcp, 34, 80);
    292 
    293 	pm_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
    294 	pm_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
    295 }
    296 
    297 static void
    298 pmattach(parent, self, aux)
    299 	struct device *parent, *self;
    300 	void *aux;
    301 {
    302 	struct pm_softc *sc = (struct pm_softc *)self;
    303 	struct ibus_attach_args *ia = aux;
    304 	struct wsemuldisplaydev_attach_args waa;
    305 	struct hwcmap256 *cm;
    306 	int console, i;
    307 
    308 	console = (ia->ia_addr == pm_consaddr);
    309 	if (console) {
    310 		sc->sc_dc = &pm_console_dc;
    311 		sc->nscreens = 1;
    312 	}
    313 	else {
    314 		sc->sc_dc = (struct fb_devconfig *)
    315 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    316 		pm_getdevconfig(ia->ia_addr, sc->sc_dc);
    317 	}
    318 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
    319 	    sc->sc_dc->dc_depth);
    320 
    321 	cm = &sc->sc_cmap;
    322 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
    323 	for (i = 1; i < CMAP_SIZE; i++) {
    324 		cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
    325 	}
    326 	sc->magic_x = PCC_MAGIC_X;
    327 	sc->magic_y = PCC_MAGIC_Y;
    328 	sc->sc_pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
    329 	sc->sc_vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_BT478);
    330 	sc->sc_pcccmdr = 0;
    331 
    332 	/* pm emits no interrupt */
    333 
    334 	waa.console = console;
    335 	waa.scrdata = &pm_screenlist;
    336 	waa.accessops = &pm_accessops;
    337 	waa.accesscookie = sc;
    338 
    339 	config_found(self, &waa, wsemuldisplaydevprint);
    340 }
    341 
    342 int
    343 pm_cnattach(addr)
    344 	paddr_t addr;
    345 {
    346 	u_int32_t v = MIPS_PHYS_TO_KSEG1(addr);
    347 	struct fb_devconfig *dcp = &pm_console_dc;
    348 	long defattr;
    349 
    350 	if (badaddr((char *)v, 4))
    351 		return (0);
    352 
    353 	pm_getdevconfig(v, dcp);
    354 	rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    355 	wsdisplay_cnattach(&pm_stdscreen, &dcp->dc_rcons,
    356 			   0, 0, defattr);
    357 
    358 	pm_consaddr = v;
    359 	return (1);
    360 }
    361 
    362 static int
    363 pmioctl(v, cmd, data, flag, p)
    364 	void *v;
    365 	u_long cmd;
    366 	caddr_t data;
    367 	int flag;
    368 	struct proc *p;
    369 {
    370 	struct pm_softc *sc = v;
    371 	struct fb_devconfig *dc = sc->sc_dc;
    372 	int turnoff, error;
    373 
    374 	switch (cmd) {
    375 	case WSDISPLAYIO_GTYPE:
    376 		*(u_int *)data = (dc->dc_depth == 8)
    377 			? WSDISPLAY_TYPE_PM_COLOR : WSDISPLAY_TYPE_PM_MONO;
    378 		return (0);
    379 
    380 	case WSDISPLAYIO_GINFO:
    381 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    382 		wsd_fbip->height = sc->sc_dc->dc_ht;
    383 		wsd_fbip->width = sc->sc_dc->dc_wid;
    384 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    385 		wsd_fbip->cmsize = CMAP_SIZE;
    386 #undef fbt
    387 		return (0);
    388 
    389 	case WSDISPLAYIO_GETCMAP:
    390 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    391 
    392 	case WSDISPLAYIO_PUTCMAP:
    393 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
    394 		if (error == 0)
    395 			bt478_loadcmap(sc);
    396 		return (error);
    397 
    398 	case WSDISPLAYIO_SVIDEO:
    399 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    400 		if ((dc->dc_blanked == 0) ^ turnoff) {
    401 			dc->dc_blanked = turnoff;
    402 #if 0 /* XXX later XXX */
    403   DS3100 Functional Specification Revision 1.3 says;
    404   be blanked by using the cursor plane control bits to force the output
    405   of both planes and changing VDAC overlay map entry 12 to 0x000000.
    406 #endif
    407 		}
    408 		return (0);
    409 
    410 	case WSDISPLAYIO_GVIDEO:
    411 		*(u_int *)data = dc->dc_blanked ?
    412 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    413 		return (0);
    414 
    415 	case WSDISPLAYIO_GCURPOS:
    416 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    417 		return (0);
    418 
    419 	case WSDISPLAYIO_SCURPOS:
    420 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    421 		pcc_set_curpos(sc);
    422 		return (0);
    423 
    424 	case WSDISPLAYIO_GCURMAX:
    425 		((struct wsdisplay_curpos *)data)->x =
    426 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    427 		return (0);
    428 
    429 	case WSDISPLAYIO_GCURSOR:
    430 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    431 
    432 	case WSDISPLAYIO_SCURSOR:
    433 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    434 	}
    435 	return -1;
    436 }
    437 
    438 static int
    439 pmmmap(v, offset, prot)
    440 	void *v;
    441 	off_t offset;
    442 	int prot;
    443 {
    444 	struct pm_softc *sc = v;
    445 
    446 	if (offset >= sc->sc_dc->dc_size)
    447 		return -1;
    448 	return mips_btop(sc->sc_dc->dc_paddr + offset);
    449 }
    450 
    451 static int
    452 pm_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    453 	void *v;
    454 	const struct wsscreen_descr *type;
    455 	void **cookiep;
    456 	int *curxp, *curyp;
    457 	long *attrp;
    458 {
    459 	struct pm_softc *sc = v;
    460 	long defattr;
    461 
    462 	if (sc->nscreens > 0)
    463 		return (ENOMEM);
    464 
    465 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    466 	*curxp = 0;
    467 	*curyp = 0;
    468 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    469 	*attrp = defattr;
    470 	sc->nscreens++;
    471 	return (0);
    472 }
    473 
    474 static void
    475 pm_free_screen(v, cookie)
    476 	void *v;
    477 	void *cookie;
    478 {
    479 	struct pm_softc *sc = v;
    480 
    481 	if (sc->sc_dc == &pm_console_dc)
    482 		panic("pm_free_screen: console");
    483 
    484 	sc->nscreens--;
    485 }
    486 
    487 static int
    488 pm_show_screen(v, cookie, waitok, cb, cbarg)
    489 	void *v;
    490 	void *cookie;
    491 	int waitok;
    492 	void (*cb) __P((void *, int, int));
    493 	void *cbarg;
    494 {
    495 
    496 	return (0);
    497 }
    498 
    499 static void
    500 pminit(dc)
    501 	struct fb_devconfig *dc;
    502 {
    503 	int i, n;
    504 	u_int16_t *p = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_CSR);
    505 	struct bt478reg *vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_BT478);
    506 	struct pccreg *pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
    507 
    508 	*(u_int8_t *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PMASK) = 0xff;
    509 	pcc->pcc_cmdr = PCC_FOPB | PCC_VBHI;
    510 
    511 	i = 0;
    512 	n = (*p & KN01_CSR_MONO) ? 128 : 1;
    513 	vdac->bt_mapWA = 0;		kn01_wbflush();
    514 	do {
    515 		vdac->bt_map = 0;	kn01_wbflush();
    516 		vdac->bt_map = 0;	kn01_wbflush();
    517 		vdac->bt_map = 0;	kn01_wbflush();
    518 	} while (++i < n);
    519 	do {
    520 		vdac->bt_map = 0xff;	kn01_wbflush();
    521 		vdac->bt_map = 0xff;	kn01_wbflush();
    522 		vdac->bt_map = 0xff;	kn01_wbflush();
    523 	} while (++i < CMAP_SIZE);
    524 }
    525 
    526 static int
    527 get_cmap(sc, p)
    528 	struct pm_softc *sc;
    529 	struct wsdisplay_cmap *p;
    530 {
    531 	u_int index = p->index, count = p->count;
    532 
    533 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    534 		return (EINVAL);
    535 
    536 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    537 	    !uvm_useracc(p->green, count, B_WRITE) ||
    538 	    !uvm_useracc(p->blue, count, B_WRITE))
    539 		return (EFAULT);
    540 
    541 	copyout(&sc->sc_cmap.r[index], p->red, count);
    542 	copyout(&sc->sc_cmap.r[index], p->green, count);
    543 	copyout(&sc->sc_cmap.r[index], p->blue, count);
    544 
    545 	return (0);
    546 }
    547 
    548 static int
    549 set_cmap(sc, p)
    550 	struct pm_softc *sc;
    551 	struct wsdisplay_cmap *p;
    552 {
    553 	u_int index = p->index, count = p->count;
    554 
    555 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    556 		return (EINVAL);
    557 
    558 	if (!uvm_useracc(p->red, count, B_READ) ||
    559 	    !uvm_useracc(p->green, count, B_READ) ||
    560 	    !uvm_useracc(p->blue, count, B_READ))
    561 		return (EFAULT);
    562 
    563 	copyin(p->red, &sc->sc_cmap.r[index], count);
    564 	copyin(p->green, &sc->sc_cmap.g[index], count);
    565 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    566 
    567 	return (0);
    568 }
    569 
    570 static int
    571 set_cursor(sc, p)
    572 	struct pm_softc *sc;
    573 	struct wsdisplay_cursor *p;
    574 {
    575 #define	cc (&sc->sc_cursor)
    576 	int v, index, count;
    577 
    578 	v = p->which;
    579 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    580 		index = p->cmap.index;
    581 		count = p->cmap.count;
    582 		if (index >= 2 || (index + count) > 2)
    583 			return (EINVAL);
    584 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    585 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    586 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    587 			return (EFAULT);
    588 
    589 		count = p->cmap.count;
    590 		copyin(p->cmap.red, &cc->cc_color[index], count);
    591 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    592 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    593 
    594 		bt478_load_curcmap(sc);
    595 	}
    596 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    597 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    598 			return (EINVAL);
    599 		count = (CURSOR_MAX_SIZE / NBBY) * p->size.y;
    600 		if (!uvm_useracc(p->image, count, B_READ) ||
    601 		    !uvm_useracc(p->mask, count, B_READ))
    602 			return (EFAULT);
    603 		cc->cc_size = p->size;
    604 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    605 		copyin(p->image, (caddr_t)cc->cc_image, count);
    606 		copyin(p->mask, (caddr_t)(cc->cc_image+CURSOR_MAX_SIZE), count);
    607 
    608 		pcc_load_curshape(sc);
    609 	}
    610 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    611 		cc->cc_hot = p->hot;
    612 		pcc_show_cursor(sc, p->enable);
    613 	}
    614 	if (v & WSDISPLAY_CURSOR_DOPOS) {
    615 		set_curpos(sc, &p->pos);
    616 		pcc_set_curpos(sc);
    617 	}
    618 
    619 	return (0);
    620 #undef cc
    621 }
    622 
    623 static int
    624 get_cursor(sc, p)
    625 	struct pm_softc *sc;
    626 	struct wsdisplay_cursor *p;
    627 {
    628 	return (ENOTTY); /* XXX */
    629 }
    630 
    631 static void
    632 set_curpos(sc, curpos)
    633 	struct pm_softc *sc;
    634 	struct wsdisplay_curpos *curpos;
    635 {
    636 	struct fb_devconfig *dc = sc->sc_dc;
    637 	int x = curpos->x, y = curpos->y;
    638 
    639 	if (y < 0)
    640 		y = 0;
    641 	else if (y > dc->dc_ht)
    642 		y = dc->dc_ht;
    643 	if (x < 0)
    644 		x = 0;
    645 	else if (x > dc->dc_wid)
    646 		x = dc->dc_wid;
    647 	sc->sc_cursor.cc_pos.x = x;
    648 	sc->sc_cursor.cc_pos.y = y;
    649 }
    650 
    651 static void
    652 bt478_loadcmap(sc)
    653 	struct pm_softc *sc;
    654 {
    655 	int i;
    656 	struct hwcmap256 *cm = &sc->sc_cmap;
    657 	struct bt478reg *vdac = sc->sc_vdac;
    658 
    659 	vdac->bt_mapWA = 0;		 kn01_wbflush();
    660 	for (i = 0; i < CMAP_SIZE; i++) {
    661 		vdac->bt_map = cm->r[i]; kn01_wbflush();
    662 		vdac->bt_map = cm->g[i]; kn01_wbflush();
    663 		vdac->bt_map = cm->b[i]; kn01_wbflush();
    664 	}
    665 }
    666 
    667 static void
    668 bt478_load_curcmap(sc)
    669 	struct pm_softc *sc;
    670 {
    671 	u_int8_t *cp = sc->sc_cursor.cc_color;
    672 	struct bt478reg *vdac = sc->sc_vdac;
    673 
    674 	vdac->bt_overWA = 0x04;	kn01_wbflush();
    675 	vdac->bt_over = cp[1];	kn01_wbflush();
    676 	vdac->bt_over = cp[3];	kn01_wbflush();
    677 	vdac->bt_over = cp[5];	kn01_wbflush();
    678 
    679 	vdac->bt_overWA = 0x08;	kn01_wbflush();
    680 	vdac->bt_over = 0x00;	kn01_wbflush();
    681 	vdac->bt_over = 0x00;	kn01_wbflush();
    682 	vdac->bt_over = 0x7f;	kn01_wbflush();
    683 
    684 	vdac->bt_overWA = 0x0c;	kn01_wbflush();
    685 	vdac->bt_over = cp[0];	kn01_wbflush();
    686 	vdac->bt_over = cp[2];	kn01_wbflush();
    687 	vdac->bt_over = cp[4];	kn01_wbflush();
    688 }
    689 
    690 static void
    691 pcc_load_curshape(sc)
    692 	struct pm_softc *sc;
    693 {
    694 	struct pccreg *pcc = sc->sc_pcc;
    695 	u_int32_t *bp;
    696 	int i;
    697 
    698 	pcc->pcc_cmdr = sc->sc_pcccmdr | PCC_LODSA;
    699 	kn01_wbflush();
    700 	bp = sc->sc_cursor.cc_image;
    701 	for (i = 0; i < sizeof(sc->sc_cursor.cc_image); i+=sizeof(u_int32_t)) {
    702 		pcc->pcc_memory = (u_int16_t)*bp++;
    703 		kn01_wbflush();
    704 	}
    705 	pcc->pcc_cmdr = sc->sc_pcccmdr;
    706 }
    707 
    708 static void
    709 pcc_set_curpos(sc)
    710 	struct pm_softc *sc;
    711 {
    712 	struct pccreg *pcc = sc->sc_pcc;
    713 
    714 	pcc->pcc_xpos = sc->sc_cursor.cc_pos.x + sc->magic_x;
    715 	pcc->pcc_ypos = sc->sc_cursor.cc_pos.y + sc->magic_y;
    716 }
    717 
    718 static void
    719 pcc_show_cursor(sc, enable)
    720 	struct pm_softc *sc;
    721 	int enable;
    722 {
    723 	struct pccreg *pcc = sc->sc_pcc;
    724 
    725 	if (enable)
    726 		sc->sc_pcccmdr |=  (PCC_ENPA | PCC_ENPB);
    727 	else
    728 		sc->sc_pcccmdr &= ~(PCC_ENPA | PCC_ENPB);
    729 	pcc->pcc_cmdr = sc->sc_pcccmdr;
    730 }
    731