Home | History | Annotate | Line # | Download | only in ibus
      1  1.19   tsutsui /*	$NetBSD: pm.c,v 1.19 2023/02/11 18:30:45 tsutsui Exp $	*/
      2   1.2        ad 
      3   1.2        ad /*-
      4   1.2        ad  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
      5   1.2        ad  * All rights reserved.
      6   1.2        ad  *
      7   1.2        ad  * This code is derived from software contributed to The NetBSD Foundation
      8   1.2        ad  * by Andrew Doran.
      9   1.2        ad  *
     10   1.2        ad  * Redistribution and use in source and binary forms, with or without
     11   1.2        ad  * modification, are permitted provided that the following conditions
     12   1.2        ad  * are met:
     13   1.2        ad  * 1. Redistributions of source code must retain the above copyright
     14   1.2        ad  *    notice, this list of conditions and the following disclaimer.
     15   1.2        ad  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.2        ad  *    notice, this list of conditions and the following disclaimer in the
     17   1.2        ad  *    documentation and/or other materials provided with the distribution.
     18   1.2        ad  *
     19   1.2        ad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.2        ad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.2        ad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.2        ad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.2        ad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.2        ad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.2        ad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.2        ad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.2        ad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.2        ad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.2        ad  * POSSIBILITY OF SUCH DAMAGE.
     30   1.2        ad  */
     31   1.2        ad 
     32   1.2        ad #include <sys/cdefs.h>
     33  1.19   tsutsui __KERNEL_RCSID(0, "$NetBSD: pm.c,v 1.19 2023/02/11 18:30:45 tsutsui Exp $");
     34   1.2        ad 
     35   1.2        ad #include <sys/param.h>
     36  1.10      matt #include <sys/buf.h>
     37  1.10      matt #include <sys/bus.h>
     38   1.2        ad #include <sys/device.h>
     39   1.2        ad #include <sys/ioctl.h>
     40  1.10      matt #include <sys/intr.h>
     41  1.10      matt #include <sys/kernel.h>
     42  1.10      matt #include <sys/systm.h>
     43   1.2        ad 
     44   1.2        ad #include <dev/wscons/wsconsio.h>
     45   1.2        ad #include <dev/wscons/wsdisplayvar.h>
     46   1.2        ad #include <dev/rasops/rasops.h>
     47   1.2        ad #include <dev/wsfont/wsfont.h>
     48   1.2        ad 
     49  1.19   tsutsui #include <dev/ic/dc503reg.h>
     50  1.19   tsutsui 
     51   1.2        ad #include <pmax/pmax/kn01.h>
     52   1.2        ad 
     53   1.2        ad #include <pmax/ibus/ibusvar.h>
     54   1.2        ad #include <pmax/ibus/pmreg.h>
     55   1.2        ad 
     56   1.2        ad #include <uvm/uvm_extern.h>
     57   1.2        ad 
     58   1.2        ad #define	CURSOR_MAX_SIZE	16
     59   1.2        ad 
     60   1.2        ad struct hwcmap256 {
     61   1.2        ad 	uint8_t r[256];
     62   1.2        ad 	uint8_t g[256];
     63   1.2        ad 	uint8_t b[256];
     64   1.2        ad };
     65   1.2        ad 
     66   1.2        ad struct hwcursor64 {
     67   1.2        ad 	struct wsdisplay_curpos cc_pos;
     68   1.2        ad 	struct wsdisplay_curpos cc_hot;
     69   1.2        ad 	struct wsdisplay_curpos cc_size;
     70   1.2        ad 	uint8_t cc_color[6];
     71   1.2        ad 
     72   1.2        ad 	/*
     73   1.2        ad 	 * Max cursor size is 16x16.  The X server pads bitmap scanlines to
     74   1.2        ad 	 * a word boundary.  We take the easy route and waste some space.
     75   1.2        ad 	 */
     76   1.2        ad 	u_short cc_image[32 + 32];
     77   1.2        ad };
     78   1.2        ad 
     79   1.2        ad struct pm_softc {
     80   1.9   tsutsui 	device_t		sc_dev;
     81   1.2        ad 	size_t			sc_cmap_size;
     82   1.2        ad 	size_t			sc_fb_size;
     83   1.2        ad 	int			sc_type;
     84   1.2        ad 	int			sc_blanked;
     85   1.2        ad 	int			sc_curenb;
     86   1.2        ad 	int			sc_changed;
     87   1.2        ad 	int			sc_nscreens;
     88   1.2        ad 	struct hwcursor64	sc_cursor;
     89   1.2        ad 	struct hwcmap256	sc_cmap;
     90   1.2        ad };
     91   1.2        ad #define	WSDISPLAY_CMAP_DOLUT	0x20
     92   1.2        ad 
     93   1.9   tsutsui int	pm_match(device_t, cfdata_t, void *);
     94   1.9   tsutsui void	pm_attach(device_t, device_t, void *);
     95  1.14      flxd int	pm_check_vfb(void);
     96   1.5  christos int	pm_ioctl(void *, void *, u_long, void *, int, struct lwp *);
     97   1.4      jmmv paddr_t	pm_mmap(void *, void *, off_t, int);
     98   1.2        ad int	pm_alloc_screen(void *, const struct wsscreen_descr *,
     99   1.2        ad 				void **, int *, int *, long *);
    100   1.2        ad void	pm_free_screen(void *, void *);
    101   1.2        ad int	pm_show_screen(void *, void *, int,
    102   1.2        ad 			       void (*) (void *, int, int), void *);
    103   1.2        ad void	pm_cursor_off(void);
    104   1.2        ad void	pm_cursor_on(struct pm_softc *);
    105   1.2        ad int	pm_cnattach(void);
    106   1.2        ad void	pm_common_init(void);
    107   1.2        ad int	pm_flush(struct pm_softc *);
    108   1.2        ad int	pm_get_cmap(struct pm_softc *, struct wsdisplay_cmap *);
    109   1.2        ad int	pm_set_cmap(struct pm_softc *, struct wsdisplay_cmap *);
    110   1.2        ad int	pm_set_cursor(struct pm_softc *, struct wsdisplay_cursor *);
    111   1.2        ad int	pm_get_cursor(struct pm_softc *, struct wsdisplay_cursor *);
    112   1.2        ad void	pm_set_curpos(struct pm_softc *, struct wsdisplay_curpos *);
    113   1.2        ad void	pm_init_cmap(struct pm_softc *);
    114   1.2        ad 
    115   1.9   tsutsui CFATTACH_DECL_NEW(pm, sizeof(struct pm_softc),
    116   1.2        ad    pm_match, pm_attach, NULL, NULL);
    117   1.2        ad 
    118   1.2        ad struct rasops_info pm_ri;
    119   1.2        ad 
    120   1.2        ad struct wsscreen_descr pm_stdscreen = {
    121   1.2        ad 	"std", 0, 0,
    122   1.2        ad 	0, /* textops */
    123   1.2        ad 	0, 0,
    124   1.2        ad 	WSSCREEN_REVERSE
    125   1.2        ad };
    126   1.2        ad 
    127   1.2        ad const struct wsscreen_descr *_pm_scrlist[] = {
    128   1.2        ad 	&pm_stdscreen,
    129   1.2        ad };
    130   1.2        ad 
    131   1.2        ad const struct wsscreen_list pm_screenlist = {
    132   1.2        ad 	sizeof(_pm_scrlist) / sizeof(struct wsscreen_descr *), _pm_scrlist
    133   1.2        ad };
    134   1.2        ad 
    135   1.2        ad const struct wsdisplay_accessops pm_accessops = {
    136   1.2        ad 	pm_ioctl,
    137   1.2        ad 	pm_mmap,
    138   1.2        ad 	pm_alloc_screen,
    139   1.2        ad 	pm_free_screen,
    140   1.2        ad 	pm_show_screen,
    141   1.2        ad 	0 /* load_font */
    142   1.2        ad };
    143   1.2        ad 
    144   1.2        ad u_int	pm_creg;
    145   1.2        ad 
    146   1.2        ad int
    147   1.9   tsutsui pm_match(device_t parent, cfdata_t cf, void *aux)
    148   1.2        ad {
    149   1.2        ad 	struct ibus_attach_args *ia;
    150   1.5  christos 	void *pmaddr;
    151   1.2        ad 
    152   1.2        ad 	ia = aux;
    153   1.5  christos 	pmaddr = (void *)ia->ia_addr;
    154   1.2        ad 
    155   1.2        ad 	if (strcmp(ia->ia_name, "pm") != 0)
    156   1.2        ad 		return (0);
    157   1.2        ad 
    158   1.2        ad 	if (badaddr(pmaddr, 4))
    159   1.2        ad 		return (0);
    160   1.2        ad 
    161   1.2        ad 	return (1);
    162   1.2        ad }
    163   1.2        ad 
    164   1.2        ad void
    165   1.9   tsutsui pm_attach(device_t parent, device_t self, void *aux)
    166   1.2        ad {
    167   1.2        ad 	struct pm_softc *sc;
    168   1.2        ad 	struct rasops_info *ri;
    169   1.2        ad 	struct wsemuldisplaydev_attach_args waa;
    170   1.2        ad 	int console;
    171   1.2        ad 
    172   1.9   tsutsui 	sc = device_private(self);
    173   1.9   tsutsui 	sc->sc_dev = self;
    174   1.2        ad 	ri = &pm_ri;
    175   1.2        ad 	console = (ri->ri_bits != NULL);
    176   1.2        ad 
    177   1.8   tsutsui 	if (console) {
    178   1.2        ad 		sc->sc_nscreens = 1;
    179   1.8   tsutsui 		ri->ri_flg &= ~RI_NO_AUTO;
    180  1.14      flxd 	} else if (!pm_check_vfb()) {
    181  1.14      flxd 		printf(": VFB01/VFB02 frame buffer option not found\n");
    182  1.14      flxd 		return;
    183   1.8   tsutsui 	} else
    184   1.2        ad 		pm_common_init();
    185   1.2        ad 
    186   1.2        ad 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
    187   1.2        ad 
    188   1.2        ad 	pm_init_cmap(sc);
    189   1.2        ad 
    190   1.2        ad 	sc->sc_blanked = 0;
    191   1.2        ad 	sc->sc_curenb = 0;
    192   1.2        ad 
    193   1.2        ad 	waa.console = console;
    194   1.2        ad 	waa.scrdata = &pm_screenlist;
    195   1.2        ad 	waa.accessops = &pm_accessops;
    196   1.2        ad 	waa.accesscookie = sc;
    197   1.2        ad 
    198  1.18   thorpej 	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
    199   1.2        ad }
    200   1.2        ad 
    201  1.14      flxd int
    202  1.14      flxd pm_check_vfb(void)
    203  1.14      flxd {
    204  1.14      flxd 	int *mem;
    205  1.14      flxd 	const int magic = 0xcafebabe;
    206  1.14      flxd 
    207  1.14      flxd 	mem = (void *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_FBUF_START);
    208  1.14      flxd 
    209  1.14      flxd 	*mem = magic;
    210  1.14      flxd 	wbflush();
    211  1.14      flxd 	if (*mem != magic)
    212  1.14      flxd 		return 0;
    213  1.14      flxd 
    214  1.14      flxd 	*mem = ~magic;
    215  1.14      flxd 	wbflush();
    216  1.14      flxd 	if (*mem != ~magic)
    217  1.14      flxd 		return 0;
    218  1.14      flxd 
    219  1.14      flxd 	return 1;
    220  1.14      flxd }
    221  1.14      flxd 
    222   1.2        ad void
    223   1.2        ad pm_init_cmap(struct pm_softc *sc)
    224   1.2        ad {
    225   1.2        ad 	struct hwcmap256 *cm;
    226   1.2        ad 	struct rasops_info *ri;
    227   1.2        ad 	const uint8_t *p;
    228   1.2        ad 	int index;
    229   1.2        ad 
    230   1.2        ad 	cm = &sc->sc_cmap;
    231   1.2        ad 	ri = &pm_ri;
    232   1.2        ad 
    233   1.2        ad 	if (ri->ri_depth == 8) {
    234   1.2        ad 		p = rasops_cmap;
    235   1.2        ad 		for (index = 0; index < 256; index++, p += 3) {
    236   1.2        ad 			cm->r[index] = p[0];
    237   1.2        ad 			cm->g[index] = p[1];
    238   1.2        ad 			cm->b[index] = p[2];
    239   1.2        ad 		}
    240   1.2        ad 
    241   1.2        ad 		sc->sc_type = WSDISPLAY_TYPE_PM_COLOR;
    242   1.2        ad 		sc->sc_cmap_size = 256;
    243   1.2        ad 		sc->sc_fb_size = 0x100000;
    244   1.2        ad 	} else {
    245   1.2        ad 		cm->r[0] = 0x00;
    246   1.2        ad 		cm->g[0] = 0x00;
    247   1.2        ad 		cm->b[0] = 0x00;
    248   1.2        ad 
    249   1.2        ad 		cm->r[1] = 0x00;
    250   1.2        ad 		cm->g[1] = 0xff;
    251   1.2        ad 		cm->b[1] = 0x00;
    252   1.2        ad 
    253   1.2        ad 		sc->sc_type = WSDISPLAY_TYPE_PM_MONO;
    254   1.2        ad 		sc->sc_cmap_size = 2;
    255   1.2        ad 		sc->sc_fb_size = 0x40000;
    256   1.2        ad 	}
    257   1.2        ad }
    258   1.2        ad 
    259   1.2        ad void
    260   1.2        ad pm_common_init(void)
    261   1.2        ad {
    262   1.2        ad 	struct rasops_info *ri;
    263   1.2        ad 	int cookie, bior, i;
    264  1.19   tsutsui 	struct dc503reg *pcc;
    265   1.2        ad 	VDACRegs *vdac;
    266   1.2        ad 	uint16_t kn01csr;
    267   1.2        ad 
    268   1.2        ad 	kn01csr = *(volatile uint16_t *)MIPS_PHYS_TO_KSEG1(KN01_SYS_CSR);
    269   1.2        ad 	pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
    270   1.2        ad 	vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC);
    271   1.2        ad 	ri = &pm_ri;
    272   1.2        ad 
    273   1.2        ad 	ri->ri_flg = RI_CENTER;
    274   1.8   tsutsui 	if (ri->ri_bits == NULL)
    275   1.8   tsutsui 		ri->ri_flg |= RI_NO_AUTO;
    276   1.2        ad 	ri->ri_depth = ((kn01csr & KN01_CSR_MONO) != 0 ? 1 : 8);
    277   1.2        ad 	ri->ri_width = 1024;
    278   1.2        ad 	ri->ri_height = 864;
    279   1.2        ad 	ri->ri_stride = (ri->ri_depth == 8 ? 1024 : 2048 / 8);
    280   1.2        ad 	ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_FBUF_START);
    281   1.2        ad 
    282   1.2        ad 	/*
    283   1.2        ad 	 * Clear the screen.
    284   1.2        ad 	 */
    285   1.2        ad 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    286   1.2        ad 
    287   1.2        ad 	/*
    288   1.2        ad 	 * Get a font to use.
    289   1.2        ad 	 */
    290   1.2        ad 	bior = (ri->ri_depth == 8 ? WSDISPLAY_FONTORDER_L2R :
    291   1.2        ad 	    WSDISPLAY_FONTORDER_R2L);
    292   1.2        ad 
    293   1.2        ad 	wsfont_init();
    294   1.2        ad 	if (ri->ri_depth == 8)
    295   1.2        ad 		cookie = wsfont_find(NULL, 12, 0, 0, bior,
    296  1.11  macallan 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
    297   1.2        ad 	else
    298   1.2        ad 		cookie = wsfont_find(NULL, 8, 0, 0, bior,
    299  1.11  macallan 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
    300   1.2        ad 	if (cookie <= 0)
    301   1.2        ad 		cookie = wsfont_find(NULL, 0, 0, 0, bior,
    302  1.11  macallan 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
    303   1.2        ad 	if (cookie <= 0) {
    304   1.2        ad 		printf("pm: font table is empty\n");
    305   1.2        ad 		return;
    306   1.2        ad 	}
    307   1.2        ad 
    308   1.2        ad 	if (wsfont_lock(cookie, &ri->ri_font)) {
    309   1.2        ad 		printf("pm: couldn't lock font\n");
    310   1.2        ad 		return;
    311   1.2        ad 	}
    312   1.2        ad 	ri->ri_wsfcookie = cookie;
    313   1.2        ad 
    314   1.2        ad 	/*
    315   1.2        ad 	 * Set up the raster operations set.
    316   1.2        ad 	 */
    317   1.2        ad 	rasops_init(ri, 1000, 1000);
    318   1.2        ad 
    319   1.2        ad 	pm_stdscreen.nrows = ri->ri_rows;
    320   1.2        ad 	pm_stdscreen.ncols = ri->ri_cols;
    321   1.2        ad 	pm_stdscreen.textops = &ri->ri_ops;
    322   1.2        ad 	pm_stdscreen.capabilities = ri->ri_caps;
    323   1.2        ad 
    324   1.2        ad 	/*
    325  1.16   msaitoh 	 * Initialize the VDAC.
    326   1.2        ad 	 */
    327   1.2        ad 	*(uint8_t *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_COLMASK_START) = 0xff;
    328   1.2        ad 	wbflush();
    329   1.2        ad 
    330   1.2        ad 	vdac->overWA = 0x04; wbflush();
    331   1.2        ad 	vdac->over = 0x00; wbflush();
    332   1.2        ad 	vdac->over = 0x00; wbflush();
    333   1.2        ad 	vdac->over = 0x00; wbflush();
    334   1.2        ad 	vdac->overWA = 0x08; wbflush();
    335   1.2        ad 	vdac->over = 0x00; wbflush();
    336   1.2        ad 	vdac->over = 0x00; wbflush();
    337   1.2        ad 	vdac->over = 0x7f; wbflush();
    338   1.2        ad 	vdac->overWA = 0x0c; wbflush();
    339   1.2        ad 	vdac->over = 0xff; wbflush();
    340   1.2        ad 	vdac->over = 0xff; wbflush();
    341   1.2        ad 	vdac->over = 0xff; wbflush();
    342   1.2        ad 
    343   1.2        ad 	/*
    344   1.2        ad 	 * Set in the initial colormap.
    345   1.2        ad 	 */
    346   1.2        ad 	if (ri->ri_depth == 8) {
    347   1.2        ad 		vdac->mapWA = 0;
    348   1.2        ad 		wbflush();
    349   1.2        ad 
    350   1.2        ad 		for (i = 0; i < 256 * 3; i += 3) {
    351   1.2        ad 			vdac->map = rasops_cmap[i];
    352   1.2        ad 			wbflush();
    353   1.2        ad 			vdac->map = rasops_cmap[i + 1];
    354   1.2        ad 			wbflush();
    355   1.2        ad 			vdac->map = rasops_cmap[i + 2];
    356   1.2        ad 			wbflush();
    357   1.2        ad 		}
    358   1.2        ad 	} else {
    359   1.2        ad 		vdac->mapWA = 0;
    360   1.2        ad 		wbflush();
    361   1.2        ad 
    362   1.2        ad 		for (i = 0; i < 256; i++) {
    363   1.2        ad 			vdac->map = 0x00;
    364   1.2        ad 			wbflush();
    365   1.2        ad 			vdac->map = (i < 128 ? 0x00 : 0xff);
    366   1.2        ad 			wbflush();
    367   1.2        ad 			vdac->map = 0x00;
    368   1.2        ad 			wbflush();
    369   1.2        ad 		}
    370   1.2        ad 	}
    371   1.2        ad 
    372   1.2        ad 	/*
    373   1.2        ad 	 * Turn off the hardware cursor sprite for text mode.
    374   1.2        ad 	 */
    375  1.19   tsutsui 	pcc->cmdr = PCCCMD_FOPB | PCCCMD_VBHI;
    376   1.2        ad 	wbflush();
    377   1.2        ad 	pm_creg = 0;
    378   1.2        ad 	pm_cursor_off();
    379   1.2        ad }
    380   1.2        ad 
    381   1.2        ad void
    382   1.2        ad pm_cursor_off(void)
    383   1.2        ad {
    384  1.19   tsutsui 	struct dc503reg *pcc;
    385   1.2        ad 
    386   1.2        ad 	pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
    387  1.19   tsutsui 	pcc->cmdr = (pm_creg &= ~(PCCCMD_ENPA | PCCCMD_ENPB));
    388   1.2        ad 	wbflush();
    389   1.2        ad }
    390   1.2        ad 
    391   1.2        ad void
    392   1.2        ad pm_cursor_on(struct pm_softc *sc)
    393   1.2        ad {
    394  1.19   tsutsui 	struct dc503reg *pcc;
    395   1.2        ad 
    396   1.2        ad 	if (sc->sc_curenb) {
    397   1.2        ad 		pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
    398  1.19   tsutsui 		pcc->cmdr = (pm_creg |= (PCCCMD_ENPA | PCCCMD_ENPB));
    399   1.2        ad 		wbflush();
    400   1.2        ad 	}
    401   1.2        ad }
    402   1.2        ad 
    403   1.2        ad int
    404   1.5  christos pm_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    405   1.2        ad {
    406   1.2        ad 	struct pm_softc *sc;
    407   1.2        ad 	struct rasops_info *ri;
    408   1.2        ad 	int turnoff, rv, i;
    409  1.19   tsutsui 	struct dc503reg *pcc;
    410   1.2        ad 	VDACRegs *vdac;
    411   1.2        ad 
    412   1.2        ad 	sc = v;
    413   1.2        ad 	ri = &pm_ri;
    414   1.2        ad 	rv = 0;
    415   1.2        ad 	pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
    416   1.2        ad 	vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC);
    417   1.2        ad 
    418   1.2        ad 	switch (cmd) {
    419   1.2        ad 	case WSDISPLAYIO_GTYPE:
    420   1.2        ad 		*(u_int *)data = sc->sc_type;
    421   1.2        ad 		break;
    422   1.2        ad 
    423   1.2        ad 	case WSDISPLAYIO_SMODE:
    424   1.2        ad 		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) {
    425   1.2        ad 			pm_cursor_off();
    426   1.2        ad 			pm_init_cmap(sc);
    427   1.2        ad 			memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    428   1.2        ad 			sc->sc_curenb = 0;
    429   1.2        ad 			sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
    430   1.2        ad 		}
    431   1.2        ad 		break;
    432   1.2        ad 
    433   1.2        ad 	case WSDISPLAYIO_GINFO:
    434   1.2        ad #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    435   1.2        ad 		wsd_fbip->height = ri->ri_height;
    436   1.2        ad 		wsd_fbip->width = ri->ri_width;
    437   1.2        ad 		wsd_fbip->depth = ri->ri_depth;
    438   1.2        ad 		wsd_fbip->cmsize = sc->sc_cmap_size;
    439   1.2        ad #undef fbt
    440   1.2        ad 		break;
    441   1.2        ad 
    442   1.2        ad 	case WSDISPLAYIO_GETCMAP:
    443   1.2        ad 		rv = pm_get_cmap(sc, (struct wsdisplay_cmap *)data);
    444   1.2        ad 		break;
    445   1.2        ad 
    446   1.2        ad 	case WSDISPLAYIO_PUTCMAP:
    447   1.2        ad 		rv = pm_set_cmap(sc, (struct wsdisplay_cmap *)data);
    448   1.2        ad 		break;
    449   1.2        ad 
    450   1.2        ad 	case WSDISPLAYIO_SVIDEO:
    451   1.2        ad 		turnoff = (*(int *)data == WSDISPLAYIO_VIDEO_OFF);
    452   1.2        ad 		if ((sc->sc_blanked == 0) ^ turnoff) {
    453   1.2        ad 			sc->sc_blanked = turnoff;
    454   1.2        ad 			if (turnoff == 0) {
    455   1.2        ad 				pcc->cmdr =
    456  1.19   tsutsui 				    (pm_creg &= ~(PCCCMD_FOPA | PCCCMD_FOPB));
    457   1.2        ad 				wbflush();
    458   1.2        ad 				pm_cursor_on(sc);
    459   1.2        ad 				sc->sc_changed |= WSDISPLAY_CURSOR_DOCMAP;
    460   1.2        ad 			} else {
    461   1.2        ad 				pm_cursor_off();
    462   1.2        ad 				pcc->cmdr =
    463  1.19   tsutsui 				    (pm_creg |= (PCCCMD_FOPA | PCCCMD_FOPB));
    464   1.2        ad 				wbflush();
    465   1.2        ad 				vdac->overWA = 0x0c;
    466   1.2        ad 				wbflush();
    467   1.2        ad 				for (i = 0; i < 3; i++) {
    468   1.2        ad 					vdac->over = 0;
    469   1.2        ad 					wbflush();
    470   1.2        ad 				}
    471   1.2        ad 			}
    472   1.2        ad 		}
    473   1.2        ad 		break;
    474   1.2        ad 
    475   1.2        ad 	case WSDISPLAYIO_GVIDEO:
    476   1.2        ad 		*(u_int *)data = (sc->sc_blanked ?
    477   1.2        ad 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON);
    478   1.2        ad 		break;
    479   1.2        ad 
    480   1.2        ad 	case WSDISPLAYIO_GCURPOS:
    481   1.2        ad 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    482   1.2        ad 		break;
    483   1.2        ad 
    484   1.2        ad 	case WSDISPLAYIO_SCURPOS:
    485   1.2        ad 		pm_set_curpos(sc, (struct wsdisplay_curpos *)data);
    486   1.2        ad 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
    487   1.2        ad 		break;
    488   1.2        ad 
    489   1.2        ad 	case WSDISPLAYIO_GCURMAX:
    490   1.2        ad 		((struct wsdisplay_curpos *)data)->x =
    491   1.2        ad 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    492   1.2        ad 		break;
    493   1.2        ad 
    494   1.2        ad 	case WSDISPLAYIO_GCURSOR:
    495   1.2        ad 		rv = pm_get_cursor(sc, (struct wsdisplay_cursor *)data);
    496   1.2        ad 		break;
    497   1.2        ad 
    498   1.2        ad 	case WSDISPLAYIO_SCURSOR:
    499   1.2        ad 		rv = pm_set_cursor(sc, (struct wsdisplay_cursor *)data);
    500   1.2        ad 		break;
    501   1.2        ad 
    502   1.2        ad 	default:
    503   1.2        ad 		rv = ENOTTY;
    504   1.2        ad 		break;
    505   1.2        ad 	}
    506   1.2        ad 
    507   1.2        ad 	pm_flush(sc);
    508   1.2        ad 	return (rv);
    509   1.2        ad }
    510   1.2        ad 
    511   1.2        ad paddr_t
    512   1.4      jmmv pm_mmap(void *v, void *vs, off_t offset, int prot)
    513   1.2        ad {
    514   1.2        ad 	struct pm_softc *sc;
    515   1.2        ad 
    516   1.2        ad 	sc = v;
    517   1.2        ad 
    518   1.2        ad 	if (offset >= sc->sc_fb_size || offset < 0)
    519   1.2        ad 		return (-1);
    520   1.2        ad 
    521   1.2        ad 	return (mips_btop(KN01_PHYS_FBUF_START + offset));
    522   1.2        ad }
    523   1.2        ad 
    524   1.2        ad int
    525   1.2        ad pm_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    526   1.2        ad 		int *curxp, int *curyp, long *attrp)
    527   1.2        ad {
    528   1.2        ad 	struct pm_softc *sc;
    529   1.2        ad 	struct rasops_info *ri;
    530   1.2        ad 	long defattr;
    531   1.2        ad 
    532   1.2        ad 	sc = v;
    533   1.2        ad 	ri = &pm_ri;
    534   1.2        ad 
    535   1.2        ad 	if (sc->sc_nscreens > 0)
    536   1.2        ad 		return (ENOMEM);
    537   1.2        ad 
    538   1.2        ad 	*cookiep = ri;	 /* one and only for now */
    539   1.2        ad 	*curxp = 0;
    540   1.2        ad 	*curyp = 0;
    541   1.2        ad 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    542   1.2        ad 	*attrp = defattr;
    543   1.2        ad 	sc->sc_nscreens++;
    544   1.2        ad 	return (0);
    545   1.2        ad }
    546   1.2        ad 
    547   1.2        ad void
    548   1.2        ad pm_free_screen(void *v, void *cookie)
    549   1.2        ad {
    550   1.2        ad 
    551   1.2        ad 	panic("pm_free_screen: console");
    552   1.2        ad }
    553   1.2        ad 
    554   1.2        ad int
    555   1.2        ad pm_show_screen(void *v, void *cookie, int waitok,
    556   1.2        ad 	       void (*cb)(void *, int, int), void *cbarg)
    557   1.2        ad {
    558   1.2        ad 
    559   1.2        ad 	return (0);
    560   1.2        ad }
    561   1.2        ad 
    562   1.2        ad /* EXPORT */ int
    563   1.2        ad pm_cnattach(void)
    564   1.2        ad {
    565   1.2        ad 	struct rasops_info *ri;
    566   1.2        ad 	long defattr;
    567   1.2        ad 
    568   1.2        ad 	ri = &pm_ri;
    569   1.2        ad 
    570   1.2        ad 	pm_common_init();
    571   1.2        ad 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    572   1.2        ad 	wsdisplay_cnattach(&pm_stdscreen, ri, 0, 0, defattr);
    573   1.2        ad 	return (1);
    574   1.2        ad }
    575   1.2        ad 
    576   1.2        ad int
    577   1.2        ad pm_flush(struct pm_softc *sc)
    578   1.2        ad {
    579   1.2        ad 	VDACRegs *vdac;
    580  1.19   tsutsui 	struct dc503reg *pcc;
    581   1.2        ad 	uint8_t *cp;
    582   1.2        ad 	int v, i, x, y;
    583   1.2        ad 	u_short *p, *pe;
    584   1.2        ad 	struct hwcmap256 *cm;
    585   1.2        ad 
    586   1.2        ad 	if (sc->sc_changed == 0)
    587   1.2        ad 		return (1);
    588   1.2        ad 
    589   1.2        ad 	vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC);
    590   1.2        ad 	pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
    591   1.2        ad 	v = sc->sc_changed;
    592   1.2        ad 
    593   1.2        ad 	if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) {
    594   1.2        ad 		if (sc->sc_curenb)
    595   1.2        ad 			pm_cursor_on(sc);
    596   1.2        ad 		else
    597   1.2        ad 			pm_cursor_off();
    598   1.2        ad 	}
    599   1.2        ad 
    600   1.2        ad 	if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) != 0) {
    601   1.2        ad 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    602   1.2        ad 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    603   1.2        ad 		pcc->xpos = x + PCC_X_OFFSET;
    604   1.2        ad 		pcc->ypos = y + PCC_Y_OFFSET;
    605   1.2        ad 		wbflush();
    606   1.2        ad 	}
    607   1.2        ad 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
    608   1.2        ad 		cp = sc->sc_cursor.cc_color;
    609   1.2        ad 
    610   1.2        ad 		vdac->overWA = 0x04;
    611   1.2        ad 		wbflush();
    612   1.2        ad 		for (i = 1; i < 6; i += 2) {
    613   1.2        ad 			vdac->over = cp[i];
    614   1.2        ad 			wbflush();
    615   1.2        ad 		}
    616   1.2        ad 
    617   1.2        ad 		vdac->overWA = 0x08;
    618   1.2        ad 		wbflush();
    619   1.2        ad 		vdac->over = 0x00;
    620   1.2        ad 		wbflush();
    621   1.2        ad 		vdac->over = 0x00;
    622   1.2        ad 		wbflush();
    623   1.2        ad 		vdac->over = 0x7f;
    624   1.2        ad 		wbflush();
    625   1.2        ad 
    626   1.2        ad 		vdac->overWA = 0x0c;
    627   1.2        ad 		wbflush();
    628   1.2        ad 		for (i = 0; i < 6; i += 2) {
    629   1.2        ad 			vdac->over = cp[i];
    630   1.2        ad 			wbflush();
    631   1.2        ad 		}
    632   1.2        ad 	}
    633   1.2        ad 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
    634  1.19   tsutsui 		pcc->cmdr = (pm_creg | PCCCMD_LODSA);
    635   1.2        ad 		wbflush();
    636   1.2        ad 
    637   1.2        ad 		p = sc->sc_cursor.cc_image;
    638   1.2        ad 		x = 0xffff >> (16 - sc->sc_cursor.cc_size.x);
    639   1.2        ad 		for (pe = p + 64; p < pe; p += 2) {
    640  1.19   tsutsui 			pcc->load = *p & x;
    641   1.2        ad 			wbflush();
    642   1.2        ad 		}
    643   1.2        ad 
    644  1.19   tsutsui 		pcc->cmdr = (pm_creg &= ~PCCCMD_LODSA);
    645   1.2        ad 		wbflush();
    646   1.2        ad 	}
    647   1.2        ad 
    648   1.2        ad 	if ((v & WSDISPLAY_CMAP_DOLUT) != 0) {
    649   1.2        ad 		cm = &sc->sc_cmap;
    650   1.2        ad 
    651   1.2        ad 		vdac->mapWA = 0;
    652   1.2        ad 		wbflush();
    653   1.2        ad 
    654   1.2        ad 		if (sc->sc_cmap_size == 2) {
    655   1.2        ad 			for (i = 0; i < 128; i++) {
    656   1.2        ad 				vdac->map = 0;
    657   1.2        ad 				wbflush();
    658   1.2        ad 				vdac->map = cm->g[0];
    659   1.2        ad 				wbflush();
    660   1.2        ad 				vdac->map = 0;
    661   1.2        ad 				wbflush();
    662   1.2        ad 			}
    663   1.2        ad 			for (; i < 256; i++) {
    664   1.2        ad 				vdac->map = 0;
    665   1.2        ad 				wbflush();
    666   1.2        ad 				vdac->map = cm->g[1];
    667   1.2        ad 				wbflush();
    668   1.2        ad 				vdac->map = 0;
    669   1.2        ad 				wbflush();
    670   1.2        ad 			}
    671   1.2        ad 		} else {
    672   1.2        ad 			for (i = 0; i < sc->sc_cmap_size; i++) {
    673   1.2        ad 				vdac->map = cm->r[i];
    674   1.2        ad 				wbflush();
    675   1.2        ad 				vdac->map = cm->g[i];
    676   1.2        ad 				wbflush();
    677   1.2        ad 				vdac->map = cm->b[i];
    678   1.2        ad 				wbflush();
    679   1.2        ad 			}
    680   1.2        ad 		}
    681   1.2        ad 	}
    682   1.2        ad 
    683   1.2        ad 	sc->sc_changed = 0;
    684   1.2        ad 	return (1);
    685   1.2        ad }
    686   1.2        ad 
    687   1.2        ad int
    688   1.2        ad pm_get_cmap(struct pm_softc *sc, struct wsdisplay_cmap *p)
    689   1.2        ad {
    690   1.2        ad 	u_int index, count;
    691   1.2        ad 	int rv;
    692   1.2        ad 
    693   1.2        ad 	index = p->index;
    694   1.2        ad 	count = p->count;
    695   1.2        ad 
    696  1.13       spz 	if (index >= sc->sc_cmap_size || count > sc->sc_cmap_size - index)
    697   1.2        ad 		return (EINVAL);
    698   1.2        ad 
    699   1.2        ad 	if ((rv = copyout(&sc->sc_cmap.r[index], p->red, count)) != 0)
    700   1.2        ad 		return (rv);
    701   1.2        ad 	if ((rv = copyout(&sc->sc_cmap.g[index], p->green, count)) != 0)
    702   1.2        ad 		return (rv);
    703   1.2        ad 	return (copyout(&sc->sc_cmap.b[index], p->blue, count));
    704   1.2        ad }
    705   1.2        ad 
    706   1.2        ad int
    707   1.2        ad pm_set_cmap(struct pm_softc *sc, struct wsdisplay_cmap *p)
    708   1.2        ad {
    709   1.2        ad 	u_int index, count;
    710   1.2        ad 	int rv;
    711   1.2        ad 
    712   1.2        ad 	index = p->index;
    713   1.2        ad 	count = p->count;
    714   1.2        ad 
    715  1.13       spz 	if (index >= sc->sc_cmap_size || count > sc->sc_cmap_size - index)
    716   1.2        ad 		return (EINVAL);
    717   1.2        ad 
    718   1.2        ad 	if ((rv = copyin(p->red, &sc->sc_cmap.r[index], count)) != 0)
    719   1.2        ad 		return (rv);
    720   1.2        ad 	if ((rv = copyin(p->green, &sc->sc_cmap.g[index], count)) != 0)
    721   1.2        ad 		return (rv);
    722   1.2        ad 	if ((rv = copyin(p->blue, &sc->sc_cmap.b[index], count)) != 0)
    723   1.2        ad 		return (rv);
    724   1.2        ad 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
    725   1.2        ad 	return (0);
    726   1.2        ad }
    727   1.2        ad 
    728   1.2        ad int
    729   1.2        ad pm_set_cursor(struct pm_softc *sc, struct wsdisplay_cursor *p)
    730   1.2        ad {
    731   1.2        ad 	u_int v, index, count;
    732   1.2        ad 	struct hwcursor64 *cc;
    733   1.2        ad 	int rv;
    734   1.2        ad 
    735   1.2        ad 	v = p->which;
    736   1.2        ad 	cc = &sc->sc_cursor;
    737   1.2        ad 
    738   1.2        ad 	if ((v & WSDISPLAY_CURSOR_DOCUR) != 0)
    739   1.2        ad 		sc->sc_curenb = p->enable;
    740   1.2        ad 	if ((v & WSDISPLAY_CURSOR_DOPOS) != 0)
    741   1.2        ad 		pm_set_curpos(sc, &p->pos);
    742   1.2        ad 	if ((v & WSDISPLAY_CURSOR_DOHOT) != 0)
    743   1.2        ad 		cc->cc_hot = p->hot;
    744   1.2        ad 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
    745   1.2        ad 		index = p->cmap.index;
    746   1.2        ad 		count = p->cmap.count;
    747  1.15  riastrad 		if (index >= 2 || count > 2 - index)
    748   1.2        ad 			return (EINVAL);
    749   1.2        ad 
    750   1.2        ad 		rv = copyin(p->cmap.red, &cc->cc_color[index], count);
    751   1.2        ad 		if (rv != 0)
    752   1.2        ad 			return (rv);
    753   1.2        ad 		rv = copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    754   1.2        ad 		if (rv != 0)
    755   1.2        ad 			return (rv);
    756   1.2        ad 		rv = copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    757   1.2        ad 		if (rv != 0)
    758   1.2        ad 			return (rv);
    759   1.2        ad 	}
    760   1.2        ad 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
    761   1.2        ad 		if (p->size.x > CURSOR_MAX_SIZE ||
    762   1.2        ad 		    p->size.y > CURSOR_MAX_SIZE)
    763   1.2        ad 			return (EINVAL);
    764   1.2        ad 
    765   1.2        ad 		cc->cc_size = p->size;
    766   1.2        ad 		memset(cc->cc_image, 0, sizeof(cc->cc_image));
    767   1.2        ad 		rv = copyin(p->image, cc->cc_image, p->size.y * 4);
    768   1.2        ad 		if (rv != 0)
    769   1.2        ad 			return (rv);
    770   1.2        ad 		rv = copyin(p->mask, cc->cc_image+32, p->size.y * 4);
    771   1.2        ad 		if (rv != 0)
    772   1.2        ad 			return (rv);
    773   1.2        ad 	}
    774   1.2        ad 
    775   1.2        ad 	sc->sc_changed |= v;
    776   1.2        ad 	return (0);
    777   1.2        ad }
    778   1.2        ad 
    779   1.2        ad int
    780   1.2        ad pm_get_cursor(struct pm_softc *sc, struct wsdisplay_cursor *p)
    781   1.2        ad {
    782   1.2        ad 
    783   1.2        ad 	return (ENOTTY); /* XXX */
    784   1.2        ad }
    785   1.2        ad 
    786   1.2        ad void
    787   1.2        ad pm_set_curpos(struct pm_softc *sc, struct wsdisplay_curpos *curpos)
    788   1.2        ad {
    789   1.2        ad 	struct rasops_info *ri;
    790   1.2        ad 	int x, y;
    791   1.2        ad 
    792   1.2        ad 	ri = &pm_ri;
    793   1.2        ad 	x = curpos->x;
    794   1.2        ad 	y = curpos->y;
    795   1.2        ad 
    796   1.2        ad 	if (y < 0)
    797   1.2        ad 		y = 0;
    798   1.2        ad 	else if (y > ri->ri_height)
    799   1.2        ad 		y = ri->ri_height;
    800   1.2        ad 	if (x < 0)
    801   1.2        ad 		x = 0;
    802   1.2        ad 	else if (x > ri->ri_width)
    803   1.2        ad 		x = ri->ri_width;
    804   1.2        ad 	sc->sc_cursor.cc_pos.x = x;
    805   1.2        ad 	sc->sc_cursor.cc_pos.y = y;
    806   1.2        ad }
    807