1 /* $NetBSD: grf.c,v 1.47 2023/12/20 00:40:44 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: Utah $Hdr: grf.c 1.36 93/08/13$ 37 * 38 * @(#)grf.c 8.4 (Berkeley) 1/12/94 39 */ 40 41 /* 42 * Graphics display driver for the X68K machines. 43 * This is the hardware-independent portion of the driver. 44 * Hardware access is through the machine dependent grf switch routines. 45 */ 46 47 #include <sys/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: grf.c,v 1.47 2023/12/20 00:40:44 thorpej Exp $"); 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/device.h> 53 #include <sys/proc.h> 54 #include <sys/resourcevar.h> 55 #include <sys/ioctl.h> 56 #include <sys/conf.h> 57 58 #include <machine/cpu.h> 59 #include <machine/grfioctl.h> 60 61 #include <x68k/dev/grfvar.h> 62 #include <x68k/dev/itevar.h> 63 64 #include <uvm/uvm_extern.h> 65 66 #include <miscfs/specfs/specdev.h> 67 68 #include "ioconf.h" 69 70 #include "ite.h" 71 #if NITE == 0 72 #define iteon(u,f) 0 73 #define iteoff(u,f) 74 #define ite_reinit(u) 75 #endif 76 77 #ifdef DEBUG 78 int grfdebug = 0; 79 #define GDB_DEVNO 0x01 80 #define GDB_MMAP 0x02 81 #define GDB_IOMAP 0x04 82 #define GDB_LOCK 0x08 83 #endif 84 85 static int grfon(struct grf_softc *); 86 static int grfoff(struct grf_softc *); 87 static off_t grfaddr(struct grf_softc *, off_t); 88 static int grfmap(dev_t, void **, struct proc *); 89 static int grfunmap(dev_t, void *, struct proc *); 90 91 dev_type_open(grfopen); 92 dev_type_close(grfclose); 93 dev_type_ioctl(grfioctl); 94 dev_type_mmap(grfmmap); 95 96 const struct cdevsw grf_cdevsw = { 97 .d_open = grfopen, 98 .d_close = grfclose, 99 .d_read = nullread, 100 .d_write = nullwrite, 101 .d_ioctl = grfioctl, 102 .d_stop = nostop, 103 .d_tty = notty, 104 .d_poll = nopoll, 105 .d_mmap = grfmmap, 106 .d_kqfilter = nokqfilter, 107 .d_discard = nodiscard, 108 .d_flag = 0 109 }; 110 111 /*ARGSUSED*/ 112 int 113 grfopen(dev_t dev, int flags, int mode, struct lwp *l) 114 { 115 struct grf_softc *gp; 116 int error = 0; 117 118 gp = device_lookup_private(&grf_cd, GRFUNIT(dev)); 119 if (gp == NULL) 120 return ENXIO; 121 122 if ((gp->g_flags & GF_ALIVE) == 0) 123 return ENXIO; 124 125 if ((gp->g_flags & (GF_OPEN|GF_EXCLUDE)) == (GF_OPEN|GF_EXCLUDE)) 126 return EBUSY; 127 128 /* 129 * First open. 130 * XXX: always put in graphics mode. 131 */ 132 error = 0; 133 if ((gp->g_flags & GF_OPEN) == 0) { 134 gp->g_flags |= GF_OPEN; 135 error = grfon(gp); 136 } 137 return error; 138 } 139 140 /*ARGSUSED*/ 141 int 142 grfclose(dev_t dev, int flags, int mode, struct lwp *l) 143 { 144 struct grf_softc *gp = device_lookup_private(&grf_cd, GRFUNIT(dev)); 145 146 if ((gp->g_flags & GF_ALIVE) == 0) 147 return ENXIO; 148 149 (void) grfoff(gp); 150 gp->g_flags &= GF_ALIVE; 151 152 return 0; 153 } 154 155 /*ARGSUSED*/ 156 int 157 grfioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 158 { 159 int unit = GRFUNIT(dev); 160 struct grf_softc *gp = device_lookup_private(&grf_cd, GRFUNIT(dev)); 161 int error; 162 163 if ((gp->g_flags & GF_ALIVE) == 0) 164 return ENXIO; 165 166 error = 0; 167 switch (cmd) { 168 169 case GRFIOCGINFO: 170 memcpy(data, (void *)&gp->g_display, sizeof(struct grfinfo)); 171 break; 172 173 case GRFIOCON: 174 error = grfon(gp); 175 break; 176 177 case GRFIOCOFF: 178 error = grfoff(gp); 179 break; 180 181 case GRFIOCMAP: 182 error = grfmap(dev, (void **)data, l->l_proc); 183 break; 184 185 case GRFIOCUNMAP: 186 error = grfunmap(dev, *(void **)data, l->l_proc); 187 break; 188 189 case GRFSETVMODE: 190 error = (*gp->g_sw->gd_mode)(gp, GM_GRFSETVMODE, data); 191 if (error == 0) 192 ite_reinit(unit); 193 break; 194 195 default: 196 error = EINVAL; 197 break; 198 199 } 200 return error; 201 } 202 203 /*ARGSUSED*/ 204 paddr_t 205 grfmmap(dev_t dev, off_t off, int prot) 206 { 207 208 return grfaddr(device_lookup_private(&grf_cd, GRFUNIT(dev)), off); 209 } 210 211 int 212 grfon(struct grf_softc *gp) 213 { 214 int unit = device_unit(gp->g_device); 215 216 /* 217 * XXX: iteoff call relies on devices being in same order 218 * as ITEs and the fact that iteoff only uses the minor part 219 * of the dev arg. 220 */ 221 iteoff(unit, 2); 222 223 return (*gp->g_sw->gd_mode)(gp, GM_GRFON, (void *) 0); 224 } 225 226 int 227 grfoff(struct grf_softc *gp) 228 { 229 int unit = device_unit(gp->g_device); 230 int error; 231 232 #if 0 /* always fails in EINVAL... */ 233 (void) grfunmap(dev, (void *) 0, curproc); 234 #endif 235 error = (*gp->g_sw->gd_mode)(gp, GM_GRFOFF, (void *) 0); 236 /* XXX: see comment for iteoff above */ 237 iteon(unit, 2); 238 239 return error; 240 } 241 242 off_t 243 grfaddr(struct grf_softc *gp, off_t off) 244 { 245 struct grfinfo *gi = &gp->g_display; 246 247 /* control registers */ 248 if (off >= 0 && off < gi->gd_regsize) 249 return ((u_int)gi->gd_regaddr + off) >> PGSHIFT; 250 251 /* frame buffer */ 252 if (off >= gi->gd_regsize && off < gi->gd_regsize+gi->gd_fbsize) { 253 off -= gi->gd_regsize; 254 return ((u_int)gi->gd_fbaddr + off) >> PGSHIFT; 255 } 256 /* bogus */ 257 return -1; 258 } 259 260 int 261 grfmap(dev_t dev, void **addrp, struct proc *p) 262 { 263 struct grf_softc *gp = device_lookup_private(&grf_cd, GRFUNIT(dev)); 264 size_t len; 265 int error; 266 267 #ifdef DEBUG 268 if (grfdebug & GDB_MMAP) 269 printf("grfmap(%d): addr %p\n", p->p_pid, *addrp); 270 #endif 271 272 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize; 273 274 error = uvm_mmap_dev(p, addrp, len, dev, 0); 275 if (error == 0) 276 (void) (*gp->g_sw->gd_mode)(gp, GM_MAP, *addrp); 277 278 return error; 279 } 280 281 int 282 grfunmap(dev_t dev, void *addr, struct proc *p) 283 { 284 struct grf_softc *gp = device_lookup_private(&grf_cd, GRFUNIT(dev)); 285 vsize_t size; 286 287 #ifdef DEBUG 288 if (grfdebug & GDB_MMAP) { 289 printf("grfunmap(%d): dev %x addr %p\n", 290 p->p_pid, GRFUNIT(dev), addr); 291 } 292 #endif 293 if (addr == 0) 294 return EINVAL; /* XXX: how do we deal with this? */ 295 (void) (*gp->g_sw->gd_mode)(gp, GM_UNMAP, 0); 296 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize); 297 uvm_unmap(&p->p_vmspace->vm_map, (vaddr_t)addr, 298 (vaddr_t)addr + size); 299 300 return 0; 301 } 302