grf.c revision 1.6
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 "miscfs/specfs/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 79int grfprobe(); 80int cc_init(), cc_mode(); 81int tg_init(), tg_mode(); 82int rt_init(), rt_mode(); 83 84struct 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}; 92int ngrfdev = sizeof(grfdev) / sizeof(grfdev[0]); 93 94struct driver grfdriver = { grfprobe, "grf" }; 95struct grf_softc grf_softc[NGRF]; 96 97#ifdef DEBUG 98int 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 */ 109grfconfig() 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 == (u_int) 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 */ 155grfprobe(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 175grfinit(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) == (u_int)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*/ 195grfopen(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*/ 221grfclose(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*/ 233grfioctl(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 OGRFIOCGINFO: 245 /* argl.. no bank-member.. */ 246 bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo)-4); 247 break; 248 249 case GRFIOCGINFO: 250 bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo)); 251 break; 252 253 case GRFIOCON: 254 error = grfon(dev); 255 break; 256 257 case GRFIOCOFF: 258 error = grfoff(dev); 259 break; 260 261 case GRFIOCMAP: 262 error = grfmmap(dev, (caddr_t *)data, p); 263 break; 264 265 case GRFIOCUNMAP: 266 error = grfunmmap(dev, *(caddr_t *)data, p); 267 break; 268 269 case GRFIOCSINFO: 270 error = grfsinfo (dev, (struct grfdyninfo *) data); 271 break; 272 273 case GRFGETVMODE: 274 return grfdev[gp->g_type].gd_mode (gp, GM_GRFGETVMODE, data); 275 276 case GRFSETVMODE: 277 error = grfdev[gp->g_type].gd_mode (gp, GM_GRFSETVMODE, data); 278 if (! error) 279 { 280 /* XXX */ 281 itereinit (GRFUNIT (dev)); 282 } 283 break; 284 285 case GRFGETNUMVM: 286 return grfdev[gp->g_type].gd_mode (gp, GM_GRFGETNUMVM, data); 287 288 /* these are all hardware dependant, and have to be resolved 289 in the respective driver. */ 290 case GRFIOCPUTCMAP: 291 case GRFIOCGETCMAP: 292 case GRFIOCSSPRITEPOS: 293 case GRFIOCGSPRITEPOS: 294 case GRFIOCSSPRITEINF: 295 case GRFIOCGSPRITEINF: 296 case GRFIOCGSPRITEMAX: 297 return grfdev[gp->g_type].gd_mode (gp, GM_GRFIOCTL, cmd, data); 298 299 default: 300 /* check to see whether it's a command recognized by the 301 view code if the unit is 0 XXX */ 302 if (GRFUNIT(dev) == 0) 303 return viewioctl (dev, cmd, data, flag, p); 304 error = EINVAL; 305 break; 306 307 } 308 return(error); 309} 310 311/*ARGSUSED*/ 312grfselect(dev, rw) 313 dev_t dev; 314{ 315 if (rw == FREAD) 316 return(0); 317 return(1); 318} 319 320grflock(gp, block) 321 register struct grf_softc *gp; 322 int block; 323{ 324 struct proc *p = curproc; /* XXX */ 325 int error; 326 extern char devioc[]; 327 328#ifdef DEBUG 329 if (grfdebug & GDB_LOCK) 330 printf("grflock(%d): dev %x flags %x lockpid %x\n", 331 p->p_pid, gp-grf_softc, gp->g_flags, 332 gp->g_lockp ? gp->g_lockp->p_pid : -1); 333#endif 334 if (gp->g_lockp) { 335 if (gp->g_lockp == p) 336 return(EBUSY); 337 if (!block) 338 return(EAGAIN); 339 do { 340 gp->g_flags |= GF_WANTED; 341 if (error = tsleep((caddr_t)&gp->g_flags, 342 (PZERO+1) | PCATCH, devioc, 0)) 343 return (error); 344 } while (gp->g_lockp); 345 } 346 gp->g_lockp = p; 347 return(0); 348} 349 350grfunlock(gp) 351 register struct grf_softc *gp; 352{ 353#ifdef DEBUG 354 if (grfdebug & GDB_LOCK) 355 printf("grfunlock(%d): dev %x flags %x lockpid %d\n", 356 curproc->p_pid, gp-grf_softc, gp->g_flags, 357 gp->g_lockp ? gp->g_lockp->p_pid : -1); 358#endif 359 if (gp->g_lockp != curproc) 360 return(EBUSY); 361 if (gp->g_flags & GF_WANTED) { 362 wakeup((caddr_t)&gp->g_flags); 363 gp->g_flags &= ~GF_WANTED; 364 } 365 gp->g_lockp = NULL; 366 return(0); 367} 368 369/*ARGSUSED*/ 370grfmap(dev, off, prot) 371 dev_t dev; 372{ 373 return(grfaddr(&grf_softc[GRFUNIT(dev)], off)); 374} 375 376 377grfon(dev) 378 dev_t dev; 379{ 380 int unit = GRFUNIT(dev); 381 struct grf_softc *gp = &grf_softc[unit]; 382 383 if (gp->g_flags & GF_GRFON) 384 return 0; 385 gp->g_flags |= GF_GRFON; 386 387 /* 388 * XXX: iteoff call relies on devices being in same order 389 * as ITEs and the fact that iteoff only uses the minor part 390 * of the dev arg. 391 */ 392 iteoff(unit, 3); 393 return((*grfdev[gp->g_type].gd_mode) 394 (gp, (dev&GRFOVDEV) ? GM_GRFOVON : GM_GRFON)); 395} 396 397grfoff(dev) 398 dev_t dev; 399{ 400 int unit = GRFUNIT(dev); 401 struct grf_softc *gp = &grf_softc[unit]; 402 int error; 403 404 if (!(gp->g_flags & GF_GRFON)) 405 return 0; 406 gp->g_flags &= ~GF_GRFON; 407 408 (void) grfunmmap(dev, (caddr_t)0, curproc); 409 error = (*grfdev[gp->g_type].gd_mode) 410 (gp, (dev&GRFOVDEV) ? GM_GRFOVOFF : GM_GRFOFF); 411 /* XXX: see comment for iteoff above */ 412 iteon(unit, 2); 413 return(error); 414} 415 416grfsinfo(dev, dyninfo) 417 dev_t dev; 418 struct grfdyninfo *dyninfo; 419{ 420 int unit = GRFUNIT(dev); 421 struct grf_softc *gp = &grf_softc[unit]; 422 int error; 423 424 error = grfdev[gp->g_type].gd_mode (gp, GM_GRFCONFIG, dyninfo); 425 /* XXX: see comment for iteoff above */ 426 itereinit (unit); 427 return(error); 428} 429 430grfaddr(gp, off) 431 struct grf_softc *gp; 432 register int off; 433{ 434 register struct grfinfo *gi = &gp->g_display; 435 436 /* control registers */ 437 if (off >= 0 && off < gi->gd_regsize) 438 return(((u_int)gi->gd_regaddr + off) >> PGSHIFT); 439 440 /* frame buffer */ 441 if (off >= gi->gd_regsize && off < gi->gd_regsize+gi->gd_fbsize) { 442 off -= gi->gd_regsize; 443#ifdef BANKEDDEVPAGER 444 if (gi->gd_bank_size) 445 off %= gi->gd_bank_size; 446#endif 447 return(((u_int)gi->gd_fbaddr + off) >> PGSHIFT); 448 } 449 /* bogus */ 450 return(-1); 451} 452 453grfmmap(dev, addrp, p) 454 dev_t dev; 455 caddr_t *addrp; 456 struct proc *p; 457{ 458 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 459 int len, error; 460 struct vnode vn; 461 struct specinfo si; 462 int flags; 463 464#ifdef DEBUG 465 if (grfdebug & GDB_MMAP) 466 printf("grfmmap(%d): addr %x\n", p->p_pid, *addrp); 467#endif 468 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize; 469 flags = MAP_FILE|MAP_SHARED; 470 if (*addrp) 471 flags |= MAP_FIXED; 472 else { 473 /* 474 * XXX if no hint provided for a non-fixed mapping place it after 475 * the end of the largest possible heap. 476 * 477 * There should really be a pmap call to determine a reasonable 478 * location. 479 */ 480 *addrp = (caddr_t) round_page(p->p_vmspace->vm_daddr + MAXDSIZ); 481 } 482 bzero (&vn, sizeof (vn)); 483 bzero (&si, sizeof (si)); 484 vn.v_type = VCHR; /* XXX */ 485 vn.v_specinfo = &si; /* XXX */ 486 vn.v_rdev = dev; /* XXX */ 487 error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp, 488 (vm_size_t)len, VM_PROT_ALL, VM_PROT_ALL, flags, 489 (caddr_t)&vn, 0); 490 return(error); 491} 492 493grfunmmap(dev, addr, p) 494 dev_t dev; 495 caddr_t addr; 496 struct proc *p; 497{ 498 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 499 vm_size_t size; 500 int rv; 501 502#ifdef DEBUG 503 if (grfdebug & GDB_MMAP) 504 printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr); 505#endif 506 if (addr == 0) 507 return(EINVAL); /* XXX: how do we deal with this? */ 508 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize); 509 rv = vm_deallocate(p->p_vmspace->vm_map, (vm_offset_t)addr, size); 510 return(rv == KERN_SUCCESS ? 0 : EINVAL); 511} 512 513#ifdef BANKEDDEVPAGER 514 515int 516grfbanked_get (dev, off, prot) 517 dev_t dev; 518 off_t off; 519 int prot; 520{ 521 int unit = GRFUNIT(dev); 522 struct grf_softc *gp = &grf_softc[unit]; 523 int error, bank; 524 struct grfinfo *gi = &gp->g_display; 525 526 off -= gi->gd_regsize; 527 if (off < 0 || off >= gi->gd_fbsize) 528 return -1; 529 530 error = grfdev[gp->g_type].gd_mode (gp, GM_GRFGETBANK, &bank, off, prot); 531 return error ? -1 : bank; 532} 533 534int 535grfbanked_cur (dev) 536 dev_t dev; 537{ 538 int unit = GRFUNIT(dev); 539 struct grf_softc *gp = &grf_softc[unit]; 540 int error, bank; 541 542 error = grfdev[gp->g_type].gd_mode (gp, GM_GRFGETCURBANK, &bank); 543 return error ? -1 : bank; 544} 545 546int 547grfbanked_set (dev, bank) 548 dev_t dev; 549 int bank; 550{ 551 int unit = GRFUNIT(dev); 552 struct grf_softc *gp = &grf_softc[unit]; 553 554 return grfdev[gp->g_type].gd_mode (gp, GM_GRFSETBANK, bank) ? -1 : 0; 555} 556 557#endif /* BANKEDDEVPAGER */ 558 559#endif /* NGRF > 0 */ 560