1 /* $NetBSD: grf_compat.c,v 1.13 2003/07/15 02:43:16 lukem 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 <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: grf_compat.c,v 1.13 2003/07/15 02:43:16 lukem Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/cdefs.h> 40 #include <sys/conf.h> 41 #include <sys/device.h> 42 #include <sys/errno.h> 43 #include <sys/ioctl.h> 44 #include <sys/malloc.h> 45 #include <sys/mman.h> 46 #include <sys/proc.h> 47 #include <sys/resourcevar.h> 48 #include <sys/vnode.h> 49 50 #include <machine/autoconf.h> 51 #include <machine/bus.h> 52 #include <machine/grfioctl.h> 53 54 #include <mac68k/nubus/nubus.h> 55 #include <mac68k/dev/grfvar.h> 56 #include <mac68k/dev/macfbvar.h> 57 58 #include <miscfs/specfs/specdev.h> 59 60 #include <uvm/uvm_extern.h> 61 #include <uvm/uvm_map.h> 62 63 dev_type_open(grfopen); 64 dev_type_close(grfclose); 65 dev_type_ioctl(grfioctl); 66 dev_type_mmap(grfmmap); 67 68 const struct cdevsw grf_cdevsw = { 69 grfopen, grfclose, noread, nowrite, grfioctl, 70 nostop, notty, nopoll, grfmmap, nokqfilter, 71 }; 72 73 void grf_scinit __P((struct grf_softc *, const char *, int)); 74 void grf_init __P((int)); 75 void grfattach __P((int)); 76 int grfmap __P((dev_t, struct macfb_softc *, caddr_t *, struct proc *)); 77 int grfunmap __P((dev_t, struct macfb_softc *, caddr_t, struct proc *)); 78 79 /* Non-private for the benefit of libkvm. */ 80 struct grf_softc *grf_softc; 81 int numgrf = 0; 82 83 /* 84 * Initialize a softc to sane defaults. 85 */ 86 void 87 grf_scinit(sc, name, unit) 88 struct grf_softc *sc; 89 const char *name; 90 int unit; 91 { 92 memset(sc, 0, sizeof(struct grf_softc)); 93 snprintf(sc->sc_xname, sizeof(sc->sc_xname), "%s%d", name, unit); 94 sc->mfb_sc = NULL; 95 } 96 97 /* 98 * (Re-)initialize the grf_softc block so that at least the requested 99 * number of elements has been allocated. If this results in more 100 * elements than we had prior to getting here, we initialize each of 101 * them to avoid problems down the road. 102 */ 103 void 104 grf_init(n) 105 int n; 106 { 107 struct grf_softc *sc; 108 int i; 109 110 if (n >= numgrf) { 111 i = numgrf; 112 numgrf = n + 1; 113 114 if (grf_softc == NULL) 115 sc = (struct grf_softc *) 116 malloc(numgrf * sizeof(*sc), 117 M_DEVBUF, M_NOWAIT); 118 else 119 sc = (struct grf_softc *) 120 realloc(grf_softc, numgrf * sizeof(*sc), 121 M_DEVBUF, M_NOWAIT); 122 if (sc == NULL) { 123 printf("WARNING: no memory for grf emulation\n"); 124 if (grf_softc != NULL) 125 free(grf_softc, M_DEVBUF); 126 return; 127 } 128 grf_softc = sc; 129 130 /* Initialize per-softc structures. */ 131 while (i < numgrf) { 132 grf_scinit(&grf_softc[i], "grf", i); 133 i++; 134 } 135 } 136 } 137 138 /* 139 * Called by main() during pseudo-device attachment. If we had a 140 * way to configure additional grf devices later, this would actually 141 * allocate enough space for them. As it stands, it's nonsensical, 142 * so other than a basic sanity check we do nothing. 143 */ 144 void 145 grfattach(n) 146 int n; 147 { 148 if (n <= 0) { 149 #ifdef DIAGNOSTIC 150 panic("grfattach: count <= 0"); 151 #endif 152 return; 153 } 154 155 #if 0 /* XXX someday, if we implement a way to attach after autoconfig */ 156 grf_init(n); 157 #endif 158 } 159 160 /* 161 * Called from macfb_attach() after setting up the frame buffer. Since 162 * there is a 1:1 correspondence between the macfb device and the grf 163 * device, the only bit of information we really need is the macfb_softc. 164 */ 165 void 166 grf_attach(sc, unit) 167 struct macfb_softc *sc; 168 int unit; 169 { 170 grf_init(unit); 171 172 if (unit < numgrf) 173 grf_softc[unit].mfb_sc = sc; 174 } 175 176 /* 177 * Standard device ops 178 */ 179 int 180 grfopen(dev, flag, mode, p) 181 dev_t dev; 182 int flag; 183 int mode; 184 struct proc *p; 185 { 186 struct grf_softc *sc; 187 int unit = GRFUNIT(dev); 188 int rv = 0; 189 190 if (grf_softc == NULL || unit >= numgrf) 191 return ENXIO; 192 193 sc = &grf_softc[unit]; 194 if (sc->mfb_sc == NULL) 195 rv = ENXIO; 196 197 return rv; 198 } 199 200 int 201 grfclose(dev, flag, mode, p) 202 dev_t dev; 203 int flag; 204 int mode; 205 struct proc *p; 206 { 207 struct grf_softc *sc; 208 int unit = GRFUNIT(dev); 209 int rv = 0; 210 211 if (grf_softc == NULL || unit >= numgrf) 212 return ENXIO; 213 214 sc = &grf_softc[unit]; 215 if (sc->mfb_sc != NULL) 216 macfb_clear(sc->mfb_sc->sc_dc); /* clear the display */ 217 else 218 rv = ENXIO; 219 220 return rv; 221 } 222 223 int 224 grfioctl(dev, cmd, data, flag, p) 225 dev_t dev; 226 u_long cmd; 227 caddr_t data; 228 int flag; 229 struct proc *p; 230 { 231 struct grf_softc *sc; 232 struct macfb_devconfig *dc; 233 #if defined(GRF_COMPAT) || (NGRF > 0) 234 struct grfinfo *gd; 235 #endif /* GRF_COMPAT || (NGRF > 0) */ 236 struct grfmode *gm; 237 int unit = GRFUNIT(dev); 238 int rv; 239 240 if (grf_softc == NULL || unit >= numgrf) 241 return ENXIO; 242 243 sc = &grf_softc[unit]; 244 if (sc->mfb_sc == NULL) 245 return ENXIO; 246 247 dc = sc->mfb_sc->sc_dc; 248 249 switch (cmd) { 250 #if defined(GRF_COMPAT) || (NGRF > 0) 251 case GRFIOCGINFO: 252 gd = (struct grfinfo *)data; 253 memset(gd, 0, sizeof(struct grfinfo)); 254 gd->gd_fbaddr = (caddr_t)dc->dc_paddr; 255 gd->gd_fbsize = dc->dc_size; 256 gd->gd_colors = (short)(1 << dc->dc_depth); 257 gd->gd_planes = (short)dc->dc_depth; 258 gd->gd_fbwidth = dc->dc_wid; 259 gd->gd_fbheight = dc->dc_ht; 260 gd->gd_fbrowbytes = dc->dc_rowbytes; 261 gd->gd_dwidth = dc->dc_raster.width; 262 gd->gd_dheight = dc->dc_raster.height; 263 rv = 0; 264 break; 265 #endif /* GRF_COMPAT || (NGRF > 0) */ 266 267 case GRFIOCON: 268 case GRFIOCOFF: 269 /* Nothing to do */ 270 rv = 0; 271 break; 272 273 #if defined(GRF_COMPAT) || (NGRF > 0) 274 case GRFIOCMAP: 275 rv = grfmap(dev, sc->mfb_sc, (caddr_t *)data, p); 276 break; 277 278 case GRFIOCUNMAP: 279 rv = grfunmap(dev, sc->mfb_sc, *(caddr_t *)data, p); 280 break; 281 #endif /* GRF_COMPAT || (NGRF > 0) */ 282 283 case GRFIOCGMODE: 284 gm = (struct grfmode *)data; 285 memset(gm, 0, sizeof(struct grfmode)); 286 gm->fbbase = (char *)dc->dc_vaddr; 287 gm->fbsize = dc->dc_size; 288 gm->fboff = dc->dc_offset; 289 gm->rowbytes = dc->dc_rowbytes; 290 gm->width = dc->dc_wid; 291 gm->height = dc->dc_ht; 292 gm->psize = dc->dc_depth; 293 rv = 0; 294 break; 295 296 case GRFIOCLISTMODES: 297 case GRFIOCGETMODE: 298 case GRFIOCSETMODE: 299 /* NONE of these operations are (officially) supported. */ 300 default: 301 rv = EINVAL; 302 break; 303 } 304 return rv; 305 } 306 307 paddr_t 308 grfmmap(dev, off, prot) 309 dev_t dev; 310 off_t off; 311 int prot; 312 { 313 struct grf_softc *sc; 314 struct macfb_devconfig *dc; 315 paddr_t addr; 316 int unit = GRFUNIT(dev); 317 318 if (grf_softc == NULL || unit >= numgrf) 319 return ENXIO; 320 321 sc = &grf_softc[unit]; 322 if (sc->mfb_sc == NULL) 323 return ENXIO; 324 325 dc = sc->mfb_sc->sc_dc; 326 327 if (off >= 0 && 328 off < m68k_round_page(dc->dc_offset + dc->dc_size)) 329 addr = m68k_btop(dc->dc_paddr + off); 330 else 331 addr = (-1); /* XXX bogus */ 332 333 return addr; 334 } 335 336 int 337 grfmap(dev, sc, addrp, p) 338 dev_t dev; 339 struct macfb_softc *sc; 340 caddr_t *addrp; 341 struct proc *p; 342 { 343 struct specinfo si; 344 struct vnode vn; 345 u_long len; 346 int error, flags; 347 348 len = m68k_round_page(sc->sc_dc->dc_offset + sc->sc_dc->dc_size); 349 *addrp = (caddr_t)VM_DEFAULT_ADDRESS(p->p_vmspace->vm_daddr, len); 350 flags = MAP_SHARED | MAP_FIXED; 351 352 vn.v_type = VCHR; /* XXX */ 353 vn.v_specinfo = &si; /* XXX */ 354 vn.v_rdev = dev; /* XXX */ 355 356 error = uvm_mmap(&p->p_vmspace->vm_map, (vaddr_t *)addrp, 357 (vsize_t)len, VM_PROT_ALL, VM_PROT_ALL, 358 flags, (caddr_t)&vn, 0, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur); 359 360 /* Offset into page: */ 361 *addrp += sc->sc_dc->dc_offset; 362 363 return (error); 364 } 365 366 int 367 grfunmap(dev, sc, addr, p) 368 dev_t dev; 369 struct macfb_softc *sc; 370 caddr_t addr; 371 struct proc *p; 372 { 373 vm_size_t size; 374 375 addr -= sc->sc_dc->dc_offset; 376 377 if (addr <= 0) 378 return (-1); 379 380 size = m68k_round_page(sc->sc_dc->dc_offset + sc->sc_dc->dc_size); 381 uvm_unmap(&p->p_vmspace->vm_map, (vaddr_t)addr, (vaddr_t)addr + size); 382 return 0; 383 } 384