1 /* $NetBSD: grf_compat.c,v 1.22 2010/06/06 04:52:17 mrg Exp $ */ 2 3 /* 4 * Copyright (C) 1999 Scott Reynolds 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * macfb compatibility with legacy grf devices 32 */ 33 34 #include "opt_grf_compat.h" 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: grf_compat.c,v 1.22 2010/06/06 04:52:17 mrg Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/conf.h> 42 #include <sys/device.h> 43 #include <sys/errno.h> 44 #include <sys/ioctl.h> 45 #include <sys/malloc.h> 46 #include <sys/mman.h> 47 #include <sys/proc.h> 48 #include <sys/resourcevar.h> 49 #include <sys/vnode.h> 50 51 #include <machine/autoconf.h> 52 #include <machine/bus.h> 53 #include <machine/grfioctl.h> 54 55 #include <mac68k/nubus/nubus.h> 56 #include <mac68k/dev/grfvar.h> 57 #include <mac68k/dev/macfbvar.h> 58 59 #include <miscfs/specfs/specdev.h> 60 61 #include <uvm/uvm_extern.h> 62 #include <uvm/uvm_map.h> 63 64 dev_type_open(grfopen); 65 dev_type_close(grfclose); 66 dev_type_ioctl(grfioctl); 67 dev_type_mmap(grfmmap); 68 69 const struct cdevsw grf_cdevsw = { 70 grfopen, grfclose, noread, nowrite, grfioctl, 71 nostop, notty, nopoll, grfmmap, nokqfilter, 72 }; 73 74 void grf_scinit(struct grf_softc *, const char *, int); 75 void grf_init(int); 76 void grfattach(int); 77 int grfmap(dev_t, struct macfb_softc *, void **, struct proc *); 78 int grfunmap(dev_t, struct macfb_softc *, void *, struct proc *); 79 80 /* Non-private for the benefit of libkvm. */ 81 struct grf_softc *grf_softc; 82 int numgrf = 0; 83 84 /* 85 * Initialize a softc to sane defaults. 86 */ 87 void 88 grf_scinit(struct grf_softc *sc, const char *name, int unit) 89 { 90 memset(sc, 0, sizeof(struct grf_softc)); 91 snprintf(sc->sc_xname, sizeof(sc->sc_xname), "%s%d", name, unit); 92 sc->mfb_sc = NULL; 93 } 94 95 /* 96 * (Re-)initialize the grf_softc block so that at least the requested 97 * number of elements has been allocated. If this results in more 98 * elements than we had prior to getting here, we initialize each of 99 * them to avoid problems down the road. 100 */ 101 void 102 grf_init(int n) 103 { 104 struct grf_softc *sc; 105 int i; 106 107 if (n >= numgrf) { 108 i = numgrf; 109 numgrf = n + 1; 110 111 if (grf_softc == NULL) 112 sc = (struct grf_softc *) 113 malloc(numgrf * sizeof(*sc), 114 M_DEVBUF, M_NOWAIT); 115 else 116 sc = (struct grf_softc *) 117 realloc(grf_softc, numgrf * sizeof(*sc), 118 M_DEVBUF, M_NOWAIT); 119 if (sc == NULL) { 120 printf("WARNING: no memory for grf emulation\n"); 121 if (grf_softc != NULL) 122 free(grf_softc, M_DEVBUF); 123 return; 124 } 125 grf_softc = sc; 126 127 /* Initialize per-softc structures. */ 128 while (i < numgrf) { 129 grf_scinit(&grf_softc[i], "grf", i); 130 i++; 131 } 132 } 133 } 134 135 /* 136 * Called by main() during pseudo-device attachment. If we had a 137 * way to configure additional grf devices later, this would actually 138 * allocate enough space for them. As it stands, it's nonsensical, 139 * so other than a basic sanity check we do nothing. 140 */ 141 void 142 grfattach(int n) 143 { 144 if (n <= 0) { 145 #ifdef DIAGNOSTIC 146 panic("grfattach: count <= 0"); 147 #endif 148 return; 149 } 150 151 #if 0 /* XXX someday, if we implement a way to attach after autoconfig */ 152 grf_init(n); 153 #endif 154 } 155 156 /* 157 * Called from macfb_attach() after setting up the frame buffer. Since 158 * there is a 1:1 correspondence between the macfb device and the grf 159 * device, the only bit of information we really need is the macfb_softc. 160 */ 161 void 162 grf_attach(struct macfb_softc *sc, int unit) 163 { 164 165 grf_init(unit); 166 if (unit < numgrf) 167 grf_softc[unit].mfb_sc = sc; 168 } 169 170 /* 171 * Standard device ops 172 */ 173 int 174 grfopen(dev_t dev, int flag, int mode, struct lwp *l) 175 { 176 struct grf_softc *sc; 177 int unit = GRFUNIT(dev); 178 int rv = 0; 179 180 if (grf_softc == NULL || unit >= numgrf) 181 return ENXIO; 182 183 sc = &grf_softc[unit]; 184 if (sc->mfb_sc == NULL) 185 rv = ENXIO; 186 187 return rv; 188 } 189 190 int 191 grfclose(dev_t dev, int flag, int mode, struct lwp *l) 192 { 193 struct grf_softc *sc; 194 int unit = GRFUNIT(dev); 195 int rv = 0; 196 197 if (grf_softc == NULL || unit >= numgrf) 198 return ENXIO; 199 200 sc = &grf_softc[unit]; 201 if (sc->mfb_sc != NULL) 202 macfb_clear(sc->mfb_sc->sc_dc); /* clear the display */ 203 else 204 rv = ENXIO; 205 206 return rv; 207 } 208 209 int 210 grfioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 211 { 212 struct grf_softc *sc; 213 struct macfb_devconfig *dc; 214 #if defined(GRF_COMPAT) || (NGRF > 0) 215 struct grfinfo *gd; 216 #endif /* GRF_COMPAT || (NGRF > 0) */ 217 struct grfmode *gm; 218 int unit = GRFUNIT(dev); 219 int rv; 220 221 if (grf_softc == NULL || unit >= numgrf) 222 return ENXIO; 223 224 sc = &grf_softc[unit]; 225 if (sc->mfb_sc == NULL) 226 return ENXIO; 227 228 dc = sc->mfb_sc->sc_dc; 229 230 switch (cmd) { 231 #if defined(GRF_COMPAT) || (NGRF > 0) 232 case GRFIOCGINFO: 233 gd = (struct grfinfo *)data; 234 memset(gd, 0, sizeof(struct grfinfo)); 235 gd->gd_fbaddr = (void *)dc->dc_paddr; 236 gd->gd_fbsize = dc->dc_size; 237 gd->gd_colors = (short)(1 << dc->dc_depth); 238 gd->gd_planes = (short)dc->dc_depth; 239 gd->gd_fbwidth = dc->dc_wid; 240 gd->gd_fbheight = dc->dc_ht; 241 gd->gd_fbrowbytes = dc->dc_rowbytes; 242 gd->gd_dwidth = dc->dc_raster.width; 243 gd->gd_dheight = dc->dc_raster.height; 244 rv = 0; 245 break; 246 #endif /* GRF_COMPAT || (NGRF > 0) */ 247 248 case GRFIOCON: 249 case GRFIOCOFF: 250 /* Nothing to do */ 251 rv = 0; 252 break; 253 254 #if defined(GRF_COMPAT) || (NGRF > 0) 255 case GRFIOCMAP: 256 rv = grfmap(dev, sc->mfb_sc, (void **)data, l->l_proc); 257 break; 258 259 case GRFIOCUNMAP: 260 rv = grfunmap(dev, sc->mfb_sc, *(void **)data, l->l_proc); 261 break; 262 #endif /* GRF_COMPAT || (NGRF > 0) */ 263 264 case GRFIOCGMODE: 265 gm = (struct grfmode *)data; 266 memset(gm, 0, sizeof(struct grfmode)); 267 gm->fbbase = (char *)dc->dc_vaddr; 268 gm->fbsize = dc->dc_size; 269 gm->fboff = dc->dc_offset; 270 gm->rowbytes = dc->dc_rowbytes; 271 gm->width = dc->dc_wid; 272 gm->height = dc->dc_ht; 273 gm->psize = dc->dc_depth; 274 rv = 0; 275 break; 276 277 case GRFIOCLISTMODES: 278 case GRFIOCGETMODE: 279 case GRFIOCSETMODE: 280 /* NONE of these operations are (officially) supported. */ 281 default: 282 rv = EINVAL; 283 break; 284 } 285 return rv; 286 } 287 288 paddr_t 289 grfmmap(dev_t dev, off_t off, int prot) 290 { 291 struct grf_softc *sc; 292 struct macfb_devconfig *dc; 293 int unit = GRFUNIT(dev); 294 295 if (grf_softc == NULL || unit >= numgrf) 296 return ENXIO; 297 298 sc = &grf_softc[unit]; 299 if (sc->mfb_sc == NULL) 300 return ENXIO; 301 302 dc = sc->mfb_sc->sc_dc; 303 304 if ((u_int)off < m68k_round_page(dc->dc_offset + dc->dc_size)) 305 return m68k_btop(dc->dc_paddr + off); 306 307 return (-1); 308 } 309 310 int 311 grfmap(dev_t dev, struct macfb_softc *sc, void **addrp, struct proc *p) 312 { 313 struct vnode vn; 314 u_long len; 315 int error, flags; 316 317 len = m68k_round_page(sc->sc_dc->dc_offset + sc->sc_dc->dc_size); 318 *addrp = (void *)VM_DEFAULT_ADDRESS(p->p_vmspace->vm_daddr, len); 319 flags = MAP_SHARED | MAP_FIXED; 320 321 vn.v_type = VCHR; /* XXX */ 322 vn.v_rdev = dev; /* XXX */ 323 324 error = uvm_mmap(&p->p_vmspace->vm_map, (vaddr_t *)addrp, 325 (vsize_t)len, VM_PROT_ALL, VM_PROT_ALL, 326 flags, (void *)&vn, 0, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur); 327 328 /* Offset into page: */ 329 *addrp = (char*)*addrp + sc->sc_dc->dc_offset; 330 331 return (error); 332 } 333 334 int 335 grfunmap(dev_t dev, struct macfb_softc *sc, void *addr, struct proc *p) 336 { 337 vm_size_t size; 338 339 addr = (char*)addr - sc->sc_dc->dc_offset; 340 341 if (addr <= 0) 342 return (-1); 343 344 size = m68k_round_page(sc->sc_dc->dc_offset + sc->sc_dc->dc_size); 345 uvm_unmap(&p->p_vmspace->vm_map, (vaddr_t)addr, (vaddr_t)addr + size); 346 return 0; 347 } 348