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