1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * from: Utah $Hdr: grf.c 1.31 91/01/21$ 39 * 40 * @(#)grf.c 7.8 (Berkeley) 5/7/91 41 */ 42 43 /* 44 * Graphics display driver for the AMIGA 45 * This is the hardware-independent portion of the driver. 46 * Hardware access is through the grfdev routines below. 47 */ 48 49 #include "grf.h" 50 #if NGRF > 0 51 52 #include "param.h" 53 #include "proc.h" 54 #include "ioctl.h" 55 #include "file.h" 56 #include "malloc.h" 57 58 #include "device.h" 59 #include "grfioctl.h" 60 #include "grfvar.h" 61 62 #include "machine/cpu.h" 63 64 #include "vm/vm.h" 65 #include "vm/vm_kern.h" 66 #include "vm/vm_page.h" 67 #include "vm/vm_pager.h" 68 69 #include "specdev.h" 70 #include "vnode.h" 71 #include "mman.h" 72 73 #include "ite.h" 74 #if NITE == 0 75 #define iteon(u,f) 76 #define iteoff(u,f) 77 #endif 78 79 int grfprobe(); 80 int cc_init(), cc_mode(); 81 int tg_init(), tg_mode(); 82 int rt_init(), rt_mode(); 83 84 struct grfdev grfdev[] = { 85 MANUF_BUILTIN, PROD_BUILTIN_DISPLAY, 86 cc_init, cc_mode, "custom chips", 87 MANUF_UNILOWELL, PROD_UNILOWELL_A2410, 88 tg_init, tg_mode, "A2410 TIGA", 89 MANUF_MACROSYSTEM, PROD_MACROSYSTEM_RETINA, 90 rt_init, rt_mode, "Retina", 91 }; 92 int ngrfdev = sizeof(grfdev) / sizeof(grfdev[0]); 93 94 struct driver grfdriver = { grfprobe, "grf" }; 95 struct grf_softc grf_softc[NGRF]; 96 97 #ifdef DEBUG 98 int grfdebug = 0; 99 #define GDB_DEVNO 0x01 100 #define GDB_MMAP 0x02 101 #define GDB_IOMAP 0x04 102 #define GDB_LOCK 0x08 103 #endif 104 105 /* 106 * XXX: called from ite console init routine. 107 * Does just what configure will do later but without printing anything. 108 */ 109 grfconfig() 110 { 111 register caddr_t addr; 112 register struct amiga_hw *hw; 113 register struct amiga_device *ad, *nad; 114 115 for (hw = sc_table; hw->hw_type; hw++) { 116 if (!HW_ISDEV(hw, D_BITMAP)) 117 continue; 118 /* 119 * Found one, now match up with a logical unit number 120 */ 121 nad = NULL; 122 addr = hw->hw_kva; 123 for (ad = amiga_dinit; ad->amiga_driver; ad++) { 124 if (ad->amiga_driver != &grfdriver || ad->amiga_alive) 125 continue; 126 /* 127 * Wildcarded. If first, remember as possible match. 128 */ 129 if (ad->amiga_addr == NULL) { 130 if (nad == NULL) 131 nad = ad; 132 continue; 133 } 134 /* 135 * Not wildcarded. 136 * If exact match done searching, else keep looking. 137 */ 138 if (((hw->hw_manufacturer << 16) | hw->hw_product) 139 == ad->amiga_addr) { 140 nad = ad; 141 break; 142 } 143 } 144 /* 145 * Found a match, initialize 146 */ 147 if (nad && grfinit (nad, hw)) 148 nad->amiga_addr = addr; 149 } 150 } 151 152 /* 153 * Normal init routine called by configure() code 154 */ 155 grfprobe(ad) 156 struct amiga_device *ad; 157 { 158 struct grf_softc *gp = &grf_softc[ad->amiga_unit]; 159 160 /* can't reinit, as ad->amiga_addr no longer contains 161 manuf/prod information */ 162 if ((gp->g_flags & GF_ALIVE) == 0 /* && 163 !grfinit (ad) */) 164 return(0); 165 printf("grf%d: %d x %d ", ad->amiga_unit, 166 gp->g_display.gd_dwidth, gp->g_display.gd_dheight); 167 if (gp->g_display.gd_colors == 2) 168 printf("monochrome"); 169 else 170 printf("%d color", gp->g_display.gd_colors); 171 printf(" %s display\n", grfdev[gp->g_type].gd_desc); 172 return(1); 173 } 174 175 grfinit(ad, ahw) 176 struct amiga_device *ad; 177 struct amiga_hw *ahw; 178 { 179 struct grf_softc *gp = &grf_softc[ad->amiga_unit]; 180 register struct grfdev *gd; 181 182 for (gd = grfdev; gd < &grfdev[ngrfdev]; gd++) 183 if (((gd->gd_manuf << 16) | gd->gd_prod) == ad->amiga_addr) 184 break; 185 186 if (gd < &grfdev[ngrfdev] && (*gd->gd_init)(gp, ad, ahw)) { 187 gp->g_type = gd - grfdev; 188 gp->g_flags = GF_ALIVE; 189 return(1); 190 } 191 return(0); 192 } 193 194 /*ARGSUSED*/ 195 grfopen(dev, flags) 196 dev_t dev; 197 { 198 int unit = GRFUNIT(dev); 199 register struct grf_softc *gp = &grf_softc[unit]; 200 int error = 0; 201 202 if (unit >= NGRF || (gp->g_flags & GF_ALIVE) == 0) 203 return(ENXIO); 204 if ((gp->g_flags & (GF_OPEN|GF_EXCLUDE)) == (GF_OPEN|GF_EXCLUDE)) 205 return(EBUSY); 206 #if 0 207 /* 208 * First open. 209 * XXX: always put in graphics mode. 210 */ 211 error = 0; 212 if ((gp->g_flags & GF_OPEN) == 0) { 213 gp->g_flags |= GF_OPEN; 214 error = grfon(dev); 215 } 216 #endif 217 return(error); 218 } 219 220 /*ARGSUSED*/ 221 grfclose(dev, flags) 222 dev_t dev; 223 { 224 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 225 226 (void) grfoff(dev); 227 (void) grfunlock(gp); 228 gp->g_flags &= GF_ALIVE; 229 return(0); 230 } 231 232 /*ARGSUSED*/ 233 grfioctl(dev, cmd, data, flag, p) 234 dev_t dev; 235 caddr_t data; 236 struct proc *p; 237 { 238 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 239 int error; 240 241 error = 0; 242 switch (cmd) { 243 244 case GRFIOCGINFO: 245 bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo)); 246 break; 247 248 case GRFIOCON: 249 error = grfon(dev); 250 break; 251 252 case GRFIOCOFF: 253 error = grfoff(dev); 254 break; 255 256 case GRFIOCMAP: 257 error = grfmmap(dev, (caddr_t *)data, p); 258 break; 259 260 case GRFIOCUNMAP: 261 error = grfunmmap(dev, *(caddr_t *)data, p); 262 break; 263 264 case GRFIOCSINFO: 265 error = grfsinfo (dev, (struct grfdyninfo *) data); 266 break; 267 268 case GRFGETVMODE: 269 return grfdev[gp->g_type].gd_mode (gp, GM_GRFGETVMODE, data); 270 271 case GRFSETVMODE: 272 error = grfdev[gp->g_type].gd_mode (gp, GM_GRFSETVMODE, data); 273 if (! error) 274 { 275 /* XXX */ 276 itereinit (GRFUNIT (dev)); 277 } 278 break; 279 280 case GRFGETNUMVM: 281 return grfdev[gp->g_type].gd_mode (gp, GM_GRFGETNUMVM, data); 282 283 default: 284 error = EINVAL; 285 break; 286 287 } 288 return(error); 289 } 290 291 /*ARGSUSED*/ 292 grfselect(dev, rw) 293 dev_t dev; 294 { 295 if (rw == FREAD) 296 return(0); 297 return(1); 298 } 299 300 grflock(gp, block) 301 register struct grf_softc *gp; 302 int block; 303 { 304 struct proc *p = curproc; /* XXX */ 305 int error; 306 extern char devioc[]; 307 308 #ifdef DEBUG 309 if (grfdebug & GDB_LOCK) 310 printf("grflock(%d): dev %x flags %x lockpid %x\n", 311 p->p_pid, gp-grf_softc, gp->g_flags, 312 gp->g_lockp ? gp->g_lockp->p_pid : -1); 313 #endif 314 if (gp->g_lockp) { 315 if (gp->g_lockp == p) 316 return(EBUSY); 317 if (!block) 318 return(EAGAIN); 319 do { 320 gp->g_flags |= GF_WANTED; 321 if (error = tsleep((caddr_t)&gp->g_flags, 322 (PZERO+1) | PCATCH, devioc, 0)) 323 return (error); 324 } while (gp->g_lockp); 325 } 326 gp->g_lockp = p; 327 return(0); 328 } 329 330 grfunlock(gp) 331 register struct grf_softc *gp; 332 { 333 #ifdef DEBUG 334 if (grfdebug & GDB_LOCK) 335 printf("grfunlock(%d): dev %x flags %x lockpid %d\n", 336 curproc->p_pid, gp-grf_softc, gp->g_flags, 337 gp->g_lockp ? gp->g_lockp->p_pid : -1); 338 #endif 339 if (gp->g_lockp != curproc) 340 return(EBUSY); 341 if (gp->g_flags & GF_WANTED) { 342 wakeup((caddr_t)&gp->g_flags); 343 gp->g_flags &= ~GF_WANTED; 344 } 345 gp->g_lockp = NULL; 346 return(0); 347 } 348 349 /*ARGSUSED*/ 350 grfmap(dev, off, prot) 351 dev_t dev; 352 { 353 return(grfaddr(&grf_softc[GRFUNIT(dev)], off)); 354 } 355 356 357 grfon(dev) 358 dev_t dev; 359 { 360 int unit = GRFUNIT(dev); 361 struct grf_softc *gp = &grf_softc[unit]; 362 363 if (gp->g_flags & GF_GRFON) 364 return 0; 365 gp->g_flags |= GF_GRFON; 366 367 /* 368 * XXX: iteoff call relies on devices being in same order 369 * as ITEs and the fact that iteoff only uses the minor part 370 * of the dev arg. 371 */ 372 iteoff(unit, 3); 373 return((*grfdev[gp->g_type].gd_mode) 374 (gp, (dev&GRFOVDEV) ? GM_GRFOVON : GM_GRFON)); 375 } 376 377 grfoff(dev) 378 dev_t dev; 379 { 380 int unit = GRFUNIT(dev); 381 struct grf_softc *gp = &grf_softc[unit]; 382 int error; 383 384 if (!(gp->g_flags & GF_GRFON)) 385 return 0; 386 gp->g_flags &= ~GF_GRFON; 387 388 (void) grfunmmap(dev, (caddr_t)0, curproc); 389 error = (*grfdev[gp->g_type].gd_mode) 390 (gp, (dev&GRFOVDEV) ? GM_GRFOVOFF : GM_GRFOFF); 391 /* XXX: see comment for iteoff above */ 392 iteon(unit, 2); 393 return(error); 394 } 395 396 grfsinfo(dev, dyninfo) 397 dev_t dev; 398 struct grfdyninfo *dyninfo; 399 { 400 int unit = GRFUNIT(dev); 401 struct grf_softc *gp = &grf_softc[unit]; 402 int error; 403 404 error = grfdev[gp->g_type].gd_mode (gp, GM_GRFCONFIG, dyninfo); 405 /* XXX: see comment for iteoff above */ 406 itereinit (unit); 407 return(error); 408 } 409 410 grfaddr(gp, off) 411 struct grf_softc *gp; 412 register int off; 413 { 414 register struct grfinfo *gi = &gp->g_display; 415 416 /* control registers */ 417 if (off >= 0 && off < gi->gd_regsize) 418 return(((u_int)gi->gd_regaddr + off) >> PGSHIFT); 419 420 /* frame buffer */ 421 if (off >= gi->gd_regsize && off < gi->gd_regsize+gi->gd_fbsize) { 422 off -= gi->gd_regsize; 423 return(((u_int)gi->gd_fbaddr + off) >> PGSHIFT); 424 } 425 /* bogus */ 426 return(-1); 427 } 428 429 grfmmap(dev, addrp, p) 430 dev_t dev; 431 caddr_t *addrp; 432 struct proc *p; 433 { 434 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 435 int len, error; 436 struct vnode vn; 437 struct specinfo si; 438 int flags; 439 440 #ifdef DEBUG 441 if (grfdebug & GDB_MMAP) 442 printf("grfmmap(%d): addr %x\n", p->p_pid, *addrp); 443 #endif 444 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize; 445 flags = MAP_FILE|MAP_SHARED; 446 if (*addrp) 447 flags |= MAP_FIXED; 448 else 449 *addrp = (caddr_t)0x1000000; /* XXX */ 450 vn.v_type = VCHR; /* XXX */ 451 vn.v_specinfo = &si; /* XXX */ 452 vn.v_rdev = dev; /* XXX */ 453 error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp, 454 (vm_size_t)len, VM_PROT_ALL, VM_PROT_ALL, flags, 455 (caddr_t)&vn, 0); 456 return(error); 457 } 458 459 grfunmmap(dev, addr, p) 460 dev_t dev; 461 caddr_t addr; 462 struct proc *p; 463 { 464 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 465 vm_size_t size; 466 int rv; 467 468 #ifdef DEBUG 469 if (grfdebug & GDB_MMAP) 470 printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr); 471 #endif 472 if (addr == 0) 473 return(EINVAL); /* XXX: how do we deal with this? */ 474 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize); 475 rv = vm_deallocate(p->p_vmspace->vm_map, (vm_offset_t)addr, size); 476 return(rv == KERN_SUCCESS ? 0 : EINVAL); 477 } 478 479 480 #endif /* NGRF > 0 */ 481