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