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 * %sccs.include.redist.c% 11 * 12 * from: Utah $Hdr: grf.c 1.31 91/01/21$ 13 * 14 * @(#)grf.c 7.8 (Berkeley) 05/07/91 15 */ 16 17 /* 18 * Graphics display driver for the HP300. 19 * This is the hardware-independent portion of the driver. 20 * Hardware access is through the grfdev routines below. 21 */ 22 23 #include "grf.h" 24 #if NGRF > 0 25 26 #include "param.h" 27 #include "proc.h" 28 #include "ioctl.h" 29 #include "file.h" 30 #include "malloc.h" 31 32 #include "device.h" 33 #include "grfioctl.h" 34 #include "grfvar.h" 35 36 #include "machine/cpu.h" 37 38 #ifdef HPUXCOMPAT 39 #include "../hpux/hpux.h" 40 #endif 41 42 #include "vm/vm.h" 43 #include "vm/vm_kern.h" 44 #include "vm/vm_page.h" 45 #include "vm/vm_pager.h" 46 47 #include "specdev.h" 48 #include "vnode.h" 49 #include "mman.h" 50 51 #include "ite.h" 52 #if NITE == 0 53 #define iteon(u,f) 54 #define iteoff(u,f) 55 #endif 56 57 int grfprobe(); 58 int tc_init(), tc_mode(); 59 int gb_init(), gb_mode(); 60 int rb_init(), rb_mode(); 61 int dv_init(), dv_mode(); 62 63 struct grfdev grfdev[] = { 64 GID_TOPCAT, GRFBOBCAT, tc_init, tc_mode, 65 "topcat", 66 GID_GATORBOX, GRFGATOR, gb_init, gb_mode, 67 "gatorbox", 68 GID_RENAISSANCE,GRFRBOX, rb_init, rb_mode, 69 "renaissance", 70 GID_LRCATSEYE, GRFCATSEYE, tc_init, tc_mode, 71 "lo-res catseye", 72 GID_HRCCATSEYE, GRFCATSEYE, tc_init, tc_mode, 73 "hi-res catseye", 74 GID_HRMCATSEYE, GRFCATSEYE, tc_init, tc_mode, 75 "hi-res catseye", 76 GID_DAVINCI, GRFDAVINCI, dv_init, dv_mode, 77 "davinci", 78 }; 79 int ngrfdev = sizeof(grfdev) / sizeof(grfdev[0]); 80 81 struct driver grfdriver = { grfprobe, "grf" }; 82 struct grf_softc grf_softc[NGRF]; 83 84 #ifdef DEBUG 85 int grfdebug = 0; 86 #define GDB_DEVNO 0x01 87 #define GDB_MMAP 0x02 88 #define GDB_IOMAP 0x04 89 #define GDB_LOCK 0x08 90 #endif 91 92 /* 93 * XXX: called from ite console init routine. 94 * Does just what configure will do later but without printing anything. 95 */ 96 grfconfig() 97 { 98 register caddr_t addr; 99 register struct hp_hw *hw; 100 register struct hp_device *hd, *nhd; 101 102 for (hw = sc_table; hw->hw_type; hw++) { 103 if (!HW_ISDEV(hw, D_BITMAP)) 104 continue; 105 /* 106 * Found one, now match up with a logical unit number 107 */ 108 nhd = NULL; 109 addr = hw->hw_kva; 110 for (hd = hp_dinit; hd->hp_driver; hd++) { 111 if (hd->hp_driver != &grfdriver || hd->hp_alive) 112 continue; 113 /* 114 * Wildcarded. If first, remember as possible match. 115 */ 116 if (hd->hp_addr == NULL) { 117 if (nhd == NULL) 118 nhd = hd; 119 continue; 120 } 121 /* 122 * Not wildcarded. 123 * If exact match done searching, else keep looking. 124 */ 125 if (sctova(hd->hp_addr) == addr) { 126 nhd = hd; 127 break; 128 } 129 } 130 /* 131 * Found a match, initialize 132 */ 133 if (nhd && grfinit(addr, nhd->hp_unit)) 134 nhd->hp_addr = addr; 135 } 136 } 137 138 /* 139 * Normal init routine called by configure() code 140 */ 141 grfprobe(hd) 142 struct hp_device *hd; 143 { 144 struct grf_softc *gp = &grf_softc[hd->hp_unit]; 145 146 if ((gp->g_flags & GF_ALIVE) == 0 && 147 !grfinit(hd->hp_addr, hd->hp_unit)) 148 return(0); 149 printf("grf%d: %d x %d ", hd->hp_unit, 150 gp->g_display.gd_dwidth, gp->g_display.gd_dheight); 151 if (gp->g_display.gd_colors == 2) 152 printf("monochrome"); 153 else 154 printf("%d color", gp->g_display.gd_colors); 155 printf(" %s display\n", grfdev[gp->g_type].gd_desc); 156 return(1); 157 } 158 159 grfinit(addr, unit) 160 caddr_t addr; 161 { 162 struct grf_softc *gp = &grf_softc[unit]; 163 struct grfreg *gr; 164 register struct grfdev *gd; 165 166 gr = (struct grfreg *) addr; 167 if (gr->gr_id != GRFHWID) 168 return(0); 169 for (gd = grfdev; gd < &grfdev[ngrfdev]; gd++) 170 if (gd->gd_hardid == gr->gr_id2) 171 break; 172 if (gd < &grfdev[ngrfdev] && (*gd->gd_init)(gp, addr)) { 173 gp->g_display.gd_id = gd->gd_softid; 174 gp->g_type = gd - grfdev; 175 gp->g_flags = GF_ALIVE; 176 return(1); 177 } 178 return(0); 179 } 180 181 /*ARGSUSED*/ 182 grfopen(dev, flags) 183 dev_t dev; 184 { 185 int unit = GRFUNIT(dev); 186 register struct grf_softc *gp = &grf_softc[unit]; 187 int error = 0; 188 189 if (unit >= NGRF || (gp->g_flags & GF_ALIVE) == 0) 190 return(ENXIO); 191 if ((gp->g_flags & (GF_OPEN|GF_EXCLUDE)) == (GF_OPEN|GF_EXCLUDE)) 192 return(EBUSY); 193 #ifdef HPUXCOMPAT 194 /* 195 * XXX: cannot handle both HPUX and BSD processes at the same time 196 */ 197 if (curproc->p_flag & SHPUX) 198 if (gp->g_flags & GF_BSDOPEN) 199 return(EBUSY); 200 else 201 gp->g_flags |= GF_HPUXOPEN; 202 else 203 if (gp->g_flags & GF_HPUXOPEN) 204 return(EBUSY); 205 else 206 gp->g_flags |= GF_BSDOPEN; 207 #endif 208 /* 209 * First open. 210 * XXX: always put in graphics mode. 211 */ 212 error = 0; 213 if ((gp->g_flags & GF_OPEN) == 0) { 214 gp->g_flags |= GF_OPEN; 215 error = grfon(dev); 216 } 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 #ifdef HPUXCOMPAT 242 if (p->p_flag & SHPUX) 243 return(hpuxgrfioctl(dev, cmd, data, flag, p)); 244 #endif 245 error = 0; 246 switch (cmd) { 247 248 /* XXX: compatibility hack */ 249 case OGRFIOCGINFO: 250 bcopy((caddr_t)&gp->g_display, data, sizeof(struct ogrfinfo)); 251 break; 252 253 case GRFIOCGINFO: 254 bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo)); 255 break; 256 257 case GRFIOCON: 258 error = grfon(dev); 259 break; 260 261 case GRFIOCOFF: 262 error = grfoff(dev); 263 break; 264 265 case GRFIOCMAP: 266 error = grfmmap(dev, (caddr_t *)data, p); 267 break; 268 269 case GRFIOCUNMAP: 270 error = grfunmmap(dev, *(caddr_t *)data, p); 271 break; 272 273 default: 274 error = EINVAL; 275 break; 276 277 } 278 return(error); 279 } 280 281 /*ARGSUSED*/ 282 grfselect(dev, rw) 283 dev_t dev; 284 { 285 if (rw == FREAD) 286 return(0); 287 return(1); 288 } 289 290 grflock(gp, block) 291 register struct grf_softc *gp; 292 int block; 293 { 294 struct proc *p = curproc; /* XXX */ 295 int error; 296 extern char devioc[]; 297 298 #ifdef DEBUG 299 if (grfdebug & GDB_LOCK) 300 printf("grflock(%d): dev %x flags %x lockpid %x\n", 301 p->p_pid, gp-grf_softc, gp->g_flags, 302 gp->g_lockp ? gp->g_lockp->p_pid : -1); 303 #endif 304 #ifdef HPUXCOMPAT 305 if (gp->g_pid) { 306 #ifdef DEBUG 307 if (grfdebug & GDB_LOCK) 308 printf(" lockpslot %d lockslot %d lock[lockslot] %d\n", 309 gp->g_lock->gl_lockslot, gp->g_lockpslot, 310 gp->g_lock->gl_locks[gp->g_lockpslot]); 311 #endif 312 gp->g_lock->gl_lockslot = 0; 313 if (gp->g_lock->gl_locks[gp->g_lockpslot] == 0) { 314 gp->g_lockp = NULL; 315 gp->g_lockpslot = 0; 316 } 317 } 318 #endif 319 if (gp->g_lockp) { 320 if (gp->g_lockp == p) 321 return(EBUSY); 322 if (!block) 323 return(EAGAIN); 324 do { 325 gp->g_flags |= GF_WANTED; 326 if (error = tsleep((caddr_t)&gp->g_flags, 327 (PZERO+1) | PCATCH, devioc, 0)) 328 return (error); 329 } while (gp->g_lockp); 330 } 331 gp->g_lockp = p; 332 #ifdef HPUXCOMPAT 333 if (gp->g_pid) { 334 int slot = grffindpid(gp); 335 #ifdef DEBUG 336 if (grfdebug & GDB_LOCK) 337 printf(" slot %d\n", slot); 338 #endif 339 gp->g_lockpslot = gp->g_lock->gl_lockslot = slot; 340 gp->g_lock->gl_locks[slot] = 1; 341 } 342 #endif 343 return(0); 344 } 345 346 grfunlock(gp) 347 register struct grf_softc *gp; 348 { 349 #ifdef DEBUG 350 if (grfdebug & GDB_LOCK) 351 printf("grfunlock(%d): dev %x flags %x lockpid %d\n", 352 curproc->p_pid, gp-grf_softc, gp->g_flags, 353 gp->g_lockp ? gp->g_lockp->p_pid : -1); 354 #endif 355 if (gp->g_lockp != curproc) 356 return(EBUSY); 357 #ifdef HPUXCOMPAT 358 if (gp->g_pid) { 359 #ifdef DEBUG 360 if (grfdebug & GDB_LOCK) 361 printf(" lockpslot %d lockslot %d lock[lockslot] %d\n", 362 gp->g_lock->gl_lockslot, gp->g_lockpslot, 363 gp->g_lock->gl_locks[gp->g_lockpslot]); 364 #endif 365 gp->g_lock->gl_locks[gp->g_lockpslot] = 0; 366 gp->g_lockpslot = gp->g_lock->gl_lockslot = 0; 367 } 368 #endif 369 if (gp->g_flags & GF_WANTED) { 370 wakeup((caddr_t)&gp->g_flags); 371 gp->g_flags &= ~GF_WANTED; 372 } 373 gp->g_lockp = NULL; 374 return(0); 375 } 376 377 /*ARGSUSED*/ 378 grfmap(dev, off, prot) 379 dev_t dev; 380 { 381 return(grfaddr(&grf_softc[GRFUNIT(dev)], off)); 382 } 383 384 #ifdef HPUXCOMPAT 385 386 /*ARGSUSED*/ 387 hpuxgrfioctl(dev, cmd, data, flag, p) 388 dev_t dev; 389 caddr_t data; 390 struct proc *p; 391 { 392 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 393 int error; 394 395 error = 0; 396 switch (cmd) { 397 398 case GCID: 399 *(int *)data = gp->g_display.gd_id; 400 break; 401 402 case GCON: 403 error = grfon(dev); 404 break; 405 406 case GCOFF: 407 error = grfoff(dev); 408 break; 409 410 case GCLOCK: 411 error = grflock(gp, 1); 412 break; 413 414 case GCUNLOCK: 415 error = grfunlock(gp); 416 break; 417 418 case GCAON: 419 case GCAOFF: 420 break; 421 422 /* GCSTATIC is implied by our implementation */ 423 case GCSTATIC_CMAP: 424 case GCVARIABLE_CMAP: 425 break; 426 427 /* map in control regs and frame buffer */ 428 case GCMAP: 429 error = grfmmap(dev, (caddr_t *)data, p); 430 break; 431 432 case GCUNMAP: 433 error = grfunmmap(dev, *(caddr_t *)data, p); 434 /* XXX: HP-UX uses GCUNMAP to get rid of GCSLOT memory */ 435 if (error) 436 error = grflckunmmap(dev, *(caddr_t *)data); 437 break; 438 439 case GCSLOT: 440 { 441 struct grf_slot *sp = (struct grf_slot *)data; 442 443 sp->slot = grffindpid(gp); 444 if (sp->slot) { 445 error = grflckmmap(dev, (caddr_t *)&sp->addr); 446 if (error && gp->g_pid) { 447 free((caddr_t)gp->g_pid, M_DEVBUF); 448 gp->g_pid = NULL; 449 } 450 } else 451 error = EINVAL; /* XXX */ 452 break; 453 } 454 455 /* 456 * XXX: only used right now to map in rbox control registers 457 * Will be replaced in the future with a real IOMAP interface. 458 */ 459 case IOMAPMAP: 460 error = iommap(dev, (caddr_t *)data); 461 #if 0 462 /* 463 * It may not be worth kludging this (using p_devtmp) to 464 * make this work. It was an undocumented side-effect 465 * in HP-UX that the mapped address was the return value 466 * of the ioctl. The only thing I remember that counted 467 * on this behavior was the rbox X10 server. 468 */ 469 if (!error) 470 u.u_r.r_val1 = *(int *)data; /* XXX: this sux */ 471 #endif 472 break; 473 474 case IOMAPUNMAP: 475 error = iounmmap(dev, *(caddr_t *)data); 476 break; 477 478 default: 479 error = EINVAL; 480 break; 481 } 482 return(error); 483 } 484 485 #endif 486 487 grfon(dev) 488 dev_t dev; 489 { 490 int unit = GRFUNIT(dev); 491 struct grf_softc *gp = &grf_softc[unit]; 492 493 /* 494 * XXX: iteoff call relies on devices being in same order 495 * as ITEs and the fact that iteoff only uses the minor part 496 * of the dev arg. 497 */ 498 iteoff(unit, 3); 499 return((*grfdev[gp->g_type].gd_mode) 500 (gp, (dev&GRFOVDEV) ? GM_GRFOVON : GM_GRFON)); 501 } 502 503 grfoff(dev) 504 dev_t dev; 505 { 506 int unit = GRFUNIT(dev); 507 struct grf_softc *gp = &grf_softc[unit]; 508 int error; 509 510 (void) grfunmmap(dev, (caddr_t)0, curproc); 511 error = (*grfdev[gp->g_type].gd_mode) 512 (gp, (dev&GRFOVDEV) ? GM_GRFOVOFF : GM_GRFOFF); 513 /* XXX: see comment for iteoff above */ 514 iteon(unit, 2); 515 return(error); 516 } 517 518 grfaddr(gp, off) 519 struct grf_softc *gp; 520 register int off; 521 { 522 register struct grfinfo *gi = &gp->g_display; 523 524 /* control registers */ 525 if (off >= 0 && off < gi->gd_regsize) 526 return(((u_int)gi->gd_regaddr + off) >> PGSHIFT); 527 528 /* frame buffer */ 529 if (off >= gi->gd_regsize && off < gi->gd_regsize+gi->gd_fbsize) { 530 off -= gi->gd_regsize; 531 return(((u_int)gi->gd_fbaddr + off) >> PGSHIFT); 532 } 533 /* bogus */ 534 return(-1); 535 } 536 537 #ifdef HPUXCOMPAT 538 /* 539 * Convert a BSD style minor devno to HPUX style. 540 * We cannot just create HPUX style nodes as they require 24 bits 541 * of minor device number and we only have 8. 542 * XXX: This may give the wrong result for remote stats of other 543 * machines where device 10 exists. 544 */ 545 grfdevno(dev) 546 dev_t dev; 547 { 548 int unit = GRFUNIT(dev); 549 struct grf_softc *gp = &grf_softc[unit]; 550 int newdev, sc; 551 552 if (unit >= NGRF || (gp->g_flags&GF_ALIVE) == 0) 553 return(bsdtohpuxdev(dev)); 554 /* magic major number */ 555 newdev = 12 << 24; 556 /* now construct minor number */ 557 if (gp->g_display.gd_regaddr != (caddr_t)GRFIADDR) { 558 sc = patosc(gp->g_display.gd_regaddr); 559 newdev |= (sc << 16) | 0x200; 560 } 561 if (dev & GRFIMDEV) 562 newdev |= 0x02; 563 else if (dev & GRFOVDEV) 564 newdev |= 0x01; 565 #ifdef DEBUG 566 if (grfdebug & GDB_DEVNO) 567 printf("grfdevno: dev %x newdev %x\n", dev, newdev); 568 #endif 569 return(newdev); 570 } 571 #endif 572 573 grfmmap(dev, addrp, p) 574 dev_t dev; 575 caddr_t *addrp; 576 struct proc *p; 577 { 578 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 579 int len, error; 580 struct vnode vn; 581 struct specinfo si; 582 int flags; 583 584 #ifdef DEBUG 585 if (grfdebug & GDB_MMAP) 586 printf("grfmmap(%d): addr %x\n", p->p_pid, *addrp); 587 #endif 588 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize; 589 flags = MAP_FILE|MAP_SHARED; 590 if (*addrp) 591 flags |= MAP_FIXED; 592 else 593 *addrp = (caddr_t)0x1000000; /* XXX */ 594 vn.v_type = VCHR; /* XXX */ 595 vn.v_specinfo = &si; /* XXX */ 596 vn.v_rdev = dev; /* XXX */ 597 error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp, 598 (vm_size_t)len, VM_PROT_ALL, flags, (caddr_t)&vn, 0); 599 return(error); 600 } 601 602 grfunmmap(dev, addr, p) 603 dev_t dev; 604 caddr_t addr; 605 struct proc *p; 606 { 607 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 608 vm_size_t size; 609 int rv; 610 611 #ifdef DEBUG 612 if (grfdebug & GDB_MMAP) 613 printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr); 614 #endif 615 if (addr == 0) 616 return(EINVAL); /* XXX: how do we deal with this? */ 617 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize); 618 rv = vm_deallocate(p->p_vmspace->vm_map, (vm_offset_t)addr, size); 619 return(rv == KERN_SUCCESS ? 0 : EINVAL); 620 } 621 622 #ifdef HPUXCOMPAT 623 iommap(dev, addrp) 624 dev_t dev; 625 caddr_t *addrp; 626 { 627 struct proc *p = curproc; /* XXX */ 628 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 629 630 #ifdef DEBUG 631 if (grfdebug & (GDB_MMAP|GDB_IOMAP)) 632 printf("iommap(%d): addr %x\n", p->p_pid, *addrp); 633 #endif 634 return(EINVAL); 635 } 636 637 iounmmap(dev, addr) 638 dev_t dev; 639 caddr_t addr; 640 { 641 int unit = minor(dev); 642 643 #ifdef DEBUG 644 if (grfdebug & (GDB_MMAP|GDB_IOMAP)) 645 printf("iounmmap(%d): id %d addr %x\n", 646 curproc->p_pid, unit, addr); 647 #endif 648 return(0); 649 } 650 651 /* 652 * Processes involved in framebuffer mapping via GCSLOT are recorded in 653 * an array of pids. The first element is used to record the last slot used 654 * (for faster lookups). The remaining elements record up to GRFMAXLCK-1 655 * process ids. Returns a slot number between 1 and GRFMAXLCK or 0 if no 656 * slot is available. 657 */ 658 grffindpid(gp) 659 struct grf_softc *gp; 660 { 661 register short pid, *sp; 662 register int i, limit; 663 int ni; 664 665 if (gp->g_pid == NULL) { 666 gp->g_pid = (short *) 667 malloc(GRFMAXLCK * sizeof(short), M_DEVBUF, M_WAITOK); 668 bzero((caddr_t)gp->g_pid, GRFMAXLCK * sizeof(short)); 669 } 670 pid = curproc->p_pid; 671 ni = limit = gp->g_pid[0]; 672 for (i = 1, sp = &gp->g_pid[1]; i <= limit; i++, sp++) { 673 if (*sp == pid) 674 goto done; 675 if (*sp == 0) 676 ni = i; 677 } 678 i = ni; 679 if (i < limit) { 680 gp->g_pid[i] = pid; 681 goto done; 682 } 683 if (++i == GRFMAXLCK) 684 return(0); 685 gp->g_pid[0] = i; 686 gp->g_pid[i] = pid; 687 done: 688 #ifdef DEBUG 689 if (grfdebug & GDB_LOCK) 690 printf("grffindpid(%d): slot %d of %d\n", 691 pid, i, gp->g_pid[0]); 692 #endif 693 return(i); 694 } 695 696 grfrmpid(gp) 697 struct grf_softc *gp; 698 { 699 register short pid, *sp; 700 register int limit, i; 701 int mi; 702 703 if (gp->g_pid == NULL || (limit = gp->g_pid[0]) == 0) 704 return; 705 pid = curproc->p_pid; 706 limit = gp->g_pid[0]; 707 mi = 0; 708 for (i = 1, sp = &gp->g_pid[1]; i <= limit; i++, sp++) { 709 if (*sp == pid) 710 *sp = 0; 711 else if (*sp) 712 mi = i; 713 } 714 i = mi; 715 if (i < limit) 716 gp->g_pid[0] = i; 717 #ifdef DEBUG 718 if (grfdebug & GDB_LOCK) 719 printf("grfrmpid(%d): slot %d of %d\n", 720 pid, sp-gp->g_pid, gp->g_pid[0]); 721 #endif 722 } 723 724 grflckmmap(dev, addrp) 725 dev_t dev; 726 caddr_t *addrp; 727 { 728 #ifdef DEBUG 729 struct proc *p = curproc; /* XXX */ 730 731 if (grfdebug & (GDB_MMAP|GDB_LOCK)) 732 printf("grflckmmap(%d): addr %x\n", 733 p->p_pid, *addrp); 734 #endif 735 return(EINVAL); 736 } 737 738 grflckunmmap(dev, addr) 739 dev_t dev; 740 caddr_t addr; 741 { 742 #ifdef DEBUG 743 int unit = minor(dev); 744 745 if (grfdebug & (GDB_MMAP|GDB_LOCK)) 746 printf("grflckunmmap(%d): id %d addr %x\n", 747 curproc->p_pid, unit, addr); 748 #endif 749 return(EINVAL); 750 } 751 #endif /* HPUXCOMPAT */ 752 753 #endif /* NGRF > 0 */ 754