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