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