1 /* $NetBSD: grf.c,v 1.40 2011/02/08 20:20:25 rmind 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.40 2011/02/08 20:20:25 rmind 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/file.h> 57 #include <sys/malloc.h> 58 #include <sys/vnode.h> 59 #include <sys/mman.h> 60 #include <sys/conf.h> 61 62 #include <machine/cpu.h> 63 #include <machine/grfioctl.h> 64 65 #include <x68k/dev/grfvar.h> 66 #include <x68k/dev/itevar.h> 67 68 #include <uvm/uvm_extern.h> 69 #include <uvm/uvm_map.h> 70 71 #include <miscfs/specfs/specdev.h> 72 73 #include "ite.h" 74 #if NITE == 0 75 #define iteon(u,f) 0 76 #define iteoff(u,f) 77 #define ite_reinit(u) 78 #endif 79 80 #ifdef DEBUG 81 int grfdebug = 0; 82 #define GDB_DEVNO 0x01 83 #define GDB_MMAP 0x02 84 #define GDB_IOMAP 0x04 85 #define GDB_LOCK 0x08 86 #endif 87 88 static int grfon(struct grf_softc *); 89 static int grfoff(struct grf_softc *); 90 static off_t grfaddr(struct grf_softc *, off_t); 91 static int grfmap(dev_t, void **, struct proc *); 92 static int grfunmap(dev_t, void *, struct proc *); 93 94 extern struct cfdriver grf_cd; 95 96 dev_type_open(grfopen); 97 dev_type_close(grfclose); 98 dev_type_ioctl(grfioctl); 99 dev_type_mmap(grfmmap); 100 101 const struct cdevsw grf_cdevsw = { 102 grfopen, grfclose, nullread, nullwrite, grfioctl, 103 nostop, notty, nopoll, grfmmap, nokqfilter, 104 }; 105 106 /*ARGSUSED*/ 107 int 108 grfopen(dev_t dev, int flags, int mode, struct lwp *l) 109 { 110 struct grf_softc *gp; 111 int error = 0; 112 113 gp = device_lookup_private(&grf_cd, GRFUNIT(dev)); 114 if (gp == NULL) 115 return ENXIO; 116 117 if ((gp->g_flags & GF_ALIVE) == 0) 118 return ENXIO; 119 120 if ((gp->g_flags & (GF_OPEN|GF_EXCLUDE)) == (GF_OPEN|GF_EXCLUDE)) 121 return EBUSY; 122 123 /* 124 * First open. 125 * XXX: always put in graphics mode. 126 */ 127 error = 0; 128 if ((gp->g_flags & GF_OPEN) == 0) { 129 gp->g_flags |= GF_OPEN; 130 error = grfon(gp); 131 } 132 return error; 133 } 134 135 /*ARGSUSED*/ 136 int 137 grfclose(dev_t dev, int flags, int mode, struct lwp *l) 138 { 139 struct grf_softc *gp = device_lookup_private(&grf_cd, GRFUNIT(dev)); 140 141 if ((gp->g_flags & GF_ALIVE) == 0) 142 return ENXIO; 143 144 (void) grfoff(gp); 145 gp->g_flags &= GF_ALIVE; 146 147 return 0; 148 } 149 150 /*ARGSUSED*/ 151 int 152 grfioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 153 { 154 int unit = GRFUNIT(dev); 155 struct grf_softc *gp = device_lookup_private(&grf_cd, GRFUNIT(dev)); 156 int error; 157 158 if ((gp->g_flags & GF_ALIVE) == 0) 159 return ENXIO; 160 161 error = 0; 162 switch (cmd) { 163 164 case GRFIOCGINFO: 165 memcpy(data, (void *)&gp->g_display, sizeof(struct grfinfo)); 166 break; 167 168 case GRFIOCON: 169 error = grfon(gp); 170 break; 171 172 case GRFIOCOFF: 173 error = grfoff(gp); 174 break; 175 176 case GRFIOCMAP: 177 error = grfmap(dev, (void **)data, l->l_proc); 178 break; 179 180 case GRFIOCUNMAP: 181 error = grfunmap(dev, *(void **)data, l->l_proc); 182 break; 183 184 case GRFSETVMODE: 185 error = (*gp->g_sw->gd_mode)(gp, GM_GRFSETVMODE, data); 186 if (error == 0) 187 ite_reinit(unit); 188 break; 189 190 default: 191 error = EINVAL; 192 break; 193 194 } 195 return error; 196 } 197 198 /*ARGSUSED*/ 199 paddr_t 200 grfmmap(dev_t dev, off_t off, int prot) 201 { 202 203 return grfaddr(device_lookup_private(&grf_cd, GRFUNIT(dev)), off); 204 } 205 206 int 207 grfon(struct grf_softc *gp) 208 { 209 int unit = device_unit(gp->g_device); 210 211 /* 212 * XXX: iteoff call relies on devices being in same order 213 * as ITEs and the fact that iteoff only uses the minor part 214 * of the dev arg. 215 */ 216 iteoff(unit, 2); 217 218 return (*gp->g_sw->gd_mode)(gp, GM_GRFON, (void *) 0); 219 } 220 221 int 222 grfoff(struct grf_softc *gp) 223 { 224 int unit = device_unit(gp->g_device); 225 int error; 226 227 #if 0 /* always fails in EINVAL... */ 228 (void) grfunmap(dev, (void *) 0, curproc); 229 #endif 230 error = (*gp->g_sw->gd_mode)(gp, GM_GRFOFF, (void *) 0); 231 /* XXX: see comment for iteoff above */ 232 iteon(unit, 2); 233 234 return error; 235 } 236 237 off_t 238 grfaddr(struct grf_softc *gp, off_t off) 239 { 240 struct grfinfo *gi = &gp->g_display; 241 242 /* control registers */ 243 if (off >= 0 && off < gi->gd_regsize) 244 return ((u_int)gi->gd_regaddr + off) >> PGSHIFT; 245 246 /* frame buffer */ 247 if (off >= gi->gd_regsize && off < gi->gd_regsize+gi->gd_fbsize) { 248 off -= gi->gd_regsize; 249 return ((u_int)gi->gd_fbaddr + off) >> PGSHIFT; 250 } 251 /* bogus */ 252 return -1; 253 } 254 255 int 256 grfmap(dev_t dev, void **addrp, struct proc *p) 257 { 258 struct grf_softc *gp = device_lookup_private(&grf_cd, GRFUNIT(dev)); 259 int len, error; 260 struct vnode vn; 261 int flags; 262 263 #ifdef DEBUG 264 if (grfdebug & GDB_MMAP) 265 printf("grfmap(%d): addr %p\n", p->p_pid, *addrp); 266 #endif 267 268 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize; 269 flags = MAP_SHARED; 270 if (*addrp) 271 flags |= MAP_FIXED; 272 else 273 *addrp = 274 (void *)VM_DEFAULT_ADDRESS(p->p_vmspace->vm_daddr, len); 275 vn.v_type = VCHR; /* XXX */ 276 vn.v_rdev = dev; /* XXX */ 277 error = uvm_mmap(&p->p_vmspace->vm_map, (vaddr_t *)addrp, 278 (vsize_t)len, VM_PROT_ALL, VM_PROT_ALL, 279 flags, (void *)&vn, 0, 280 p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur); 281 if (error == 0) 282 (void) (*gp->g_sw->gd_mode)(gp, GM_MAP, *addrp); 283 284 return error; 285 } 286 287 int 288 grfunmap(dev_t dev, void *addr, struct proc *p) 289 { 290 struct grf_softc *gp = device_lookup_private(&grf_cd, GRFUNIT(dev)); 291 vsize_t size; 292 293 #ifdef DEBUG 294 if (grfdebug & GDB_MMAP) { 295 printf("grfunmap(%d): dev %x addr %p\n", 296 p->p_pid, GRFUNIT(dev), addr); 297 } 298 #endif 299 if (addr == 0) 300 return EINVAL; /* XXX: how do we deal with this? */ 301 (void) (*gp->g_sw->gd_mode)(gp, GM_UNMAP, 0); 302 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize); 303 uvm_unmap(&p->p_vmspace->vm_map, (vaddr_t)addr, 304 (vaddr_t)addr + size); 305 306 return 0; 307 } 308