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.6 (Berkeley) 12/16/90 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 "sys/param.h" 27 #include "sys/user.h" 28 #include "sys/proc.h" 29 #include "sys/ioctl.h" 30 #include "sys/file.h" 31 #include "sys/malloc.h" 32 33 #include "device.h" 34 #include "grfioctl.h" 35 #include "grfvar.h" 36 37 #include "../include/cpu.h" 38 39 #ifdef HPUXCOMPAT 40 #include "../hpux/hpux.h" 41 #endif 42 43 #include "vm/vm_param.h" 44 #include "vm/vm_map.h" 45 #include "vm/vm_kern.h" 46 #include "vm/vm_page.h" 47 #include "vm/vm_pager.h" 48 #include "sys/specdev.h" 49 #include "sys/vnode.h" 50 #include "sys/mman.h" 51 52 #include "ite.h" 53 #if NITE == 0 54 #define iteon(u,f) 55 #define iteoff(u,f) 56 #endif 57 58 int grfprobe(); 59 int tc_init(), tc_mode(); 60 int gb_init(), gb_mode(); 61 int rb_init(), rb_mode(); 62 int dv_init(), dv_mode(); 63 64 struct grfdev grfdev[] = { 65 GID_TOPCAT, GRFBOBCAT, tc_init, tc_mode, 66 "topcat", 67 GID_GATORBOX, GRFGATOR, gb_init, gb_mode, 68 "gatorbox", 69 GID_RENAISSANCE,GRFRBOX, rb_init, rb_mode, 70 "renaissance", 71 GID_LRCATSEYE, GRFCATSEYE, tc_init, tc_mode, 72 "lo-res catseye", 73 GID_HRCCATSEYE, GRFCATSEYE, tc_init, tc_mode, 74 "hi-res catseye", 75 GID_HRMCATSEYE, GRFCATSEYE, tc_init, tc_mode, 76 "hi-res catseye", 77 GID_DAVINCI, GRFDAVINCI, dv_init, dv_mode, 78 "davinci", 79 }; 80 int ngrfdev = sizeof(grfdev) / sizeof(grfdev[0]); 81 82 struct driver grfdriver = { grfprobe, "grf" }; 83 struct grf_softc grf_softc[NGRF]; 84 85 #ifdef DEBUG 86 int grfdebug = 0; 87 #define GDB_DEVNO 0x01 88 #define GDB_MMAP 0x02 89 #define GDB_IOMAP 0x04 90 #define GDB_LOCK 0x08 91 #endif 92 93 /* 94 * XXX: called from ite console init routine. 95 * Does just what configure will do later but without printing anything. 96 */ 97 grfconfig() 98 { 99 register caddr_t addr; 100 register struct hp_hw *hw; 101 register struct hp_device *hd, *nhd; 102 103 for (hw = sc_table; hw->hw_type; hw++) { 104 if (hw->hw_type != BITMAP) 105 continue; 106 /* 107 * Found one, now match up with a logical unit number 108 */ 109 nhd = NULL; 110 addr = hw->hw_addr; 111 for (hd = hp_dinit; hd->hp_driver; hd++) { 112 if (hd->hp_driver != &grfdriver || hd->hp_alive) 113 continue; 114 /* 115 * Wildcarded. If first, remember as possible match. 116 */ 117 if (hd->hp_addr == NULL) { 118 if (nhd == NULL) 119 nhd = hd; 120 continue; 121 } 122 /* 123 * Not wildcarded. 124 * If exact match done searching, else keep looking. 125 */ 126 if ((caddr_t)sctoaddr(hd->hp_addr) == addr) { 127 nhd = hd; 128 break; 129 } 130 } 131 /* 132 * Found a match, initialize 133 */ 134 if (nhd && grfinit(addr, nhd->hp_unit)) { 135 nhd->hp_addr = addr; 136 } 137 } 138 } 139 140 /* 141 * Normal init routine called by configure() code 142 */ 143 grfprobe(hd) 144 struct hp_device *hd; 145 { 146 struct grf_softc *gp = &grf_softc[hd->hp_unit]; 147 148 if ((gp->g_flags & GF_ALIVE) == 0 && 149 !grfinit(hd->hp_addr, hd->hp_unit)) 150 return(0); 151 printf("grf%d: %d x %d ", hd->hp_unit, 152 gp->g_display.gd_dwidth, gp->g_display.gd_dheight); 153 if (gp->g_display.gd_colors == 2) 154 printf("monochrome"); 155 else 156 printf("%d color", gp->g_display.gd_colors); 157 printf(" %s display\n", grfdev[gp->g_type].gd_desc); 158 return(1); 159 } 160 161 grfinit(addr, unit) 162 caddr_t addr; 163 { 164 struct grf_softc *gp = &grf_softc[unit]; 165 struct grfreg *gr; 166 register struct grfdev *gd; 167 168 gr = (struct grfreg *) addr; 169 if (gr->gr_id != GRFHWID) 170 return(0); 171 for (gd = grfdev; gd < &grfdev[ngrfdev]; gd++) 172 if (gd->gd_hardid == gr->gr_id2) 173 break; 174 if (gd < &grfdev[ngrfdev] && (*gd->gd_init)(gp, addr)) { 175 gp->g_display.gd_id = gd->gd_softid; 176 gp->g_type = gd - grfdev; 177 gp->g_flags = GF_ALIVE; 178 return(1); 179 } 180 return(0); 181 } 182 183 /*ARGSUSED*/ 184 grfopen(dev, flags) 185 dev_t dev; 186 { 187 int unit = GRFUNIT(dev); 188 register struct grf_softc *gp = &grf_softc[unit]; 189 int error = 0; 190 191 if (unit >= NGRF || (gp->g_flags & GF_ALIVE) == 0) 192 return(ENXIO); 193 if ((gp->g_flags & (GF_OPEN|GF_EXCLUDE)) == (GF_OPEN|GF_EXCLUDE)) 194 return(EBUSY); 195 #ifdef HPUXCOMPAT 196 /* 197 * XXX: cannot handle both HPUX and BSD processes at the same time 198 */ 199 if (u.u_procp->p_flag & SHPUX) 200 if (gp->g_flags & GF_BSDOPEN) 201 return(EBUSY); 202 else 203 gp->g_flags |= GF_HPUXOPEN; 204 else 205 if (gp->g_flags & GF_HPUXOPEN) 206 return(EBUSY); 207 else 208 gp->g_flags |= GF_BSDOPEN; 209 #endif 210 /* 211 * First open. 212 * XXX: always put in graphics mode. 213 */ 214 error = 0; 215 if ((gp->g_flags & GF_OPEN) == 0) { 216 gp->g_flags |= GF_OPEN; 217 error = grfon(dev); 218 } 219 return(error); 220 } 221 222 /*ARGSUSED*/ 223 grfclose(dev, flags) 224 dev_t dev; 225 { 226 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 227 228 (void) grfoff(dev); 229 (void) grfunlock(gp); 230 gp->g_flags &= GF_ALIVE; 231 return(0); 232 } 233 234 /*ARGSUSED*/ 235 grfioctl(dev, cmd, data, flag) 236 dev_t dev; 237 caddr_t data; 238 { 239 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 240 int error; 241 242 #ifdef HPUXCOMPAT 243 if (u.u_procp->p_flag & SHPUX) 244 return(hpuxgrfioctl(dev, cmd, data, flag)); 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); 268 break; 269 270 case GRFIOCUNMAP: 271 error = grfunmmap(dev, *(caddr_t *)data); 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 = u.u_procp; /* 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 u.u_procp->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 != u.u_procp) 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) 389 dev_t dev; 390 caddr_t data; 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); 430 break; 431 432 case GCUNMAP: 433 error = grfunmmap(dev, *(caddr_t *)data); 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); 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; 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 newdev |= ((u_int)gp->g_display.gd_regaddr-EXTIOBASE) | 0x200; 559 if (dev & GRFIMDEV) 560 newdev |= 0x02; 561 else if (dev & GRFOVDEV) 562 newdev |= 0x01; 563 #ifdef DEBUG 564 if (grfdebug & GDB_DEVNO) 565 printf("grfdevno: dev %x newdev %x\n", dev, newdev); 566 #endif 567 return(newdev); 568 } 569 #endif 570 571 grfmmap(dev, addrp) 572 dev_t dev; 573 caddr_t *addrp; 574 { 575 struct proc *p = u.u_procp; /* XXX */ 576 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 577 int len, error; 578 struct vnode vn; 579 struct specinfo si; 580 int flags; 581 582 #ifdef DEBUG 583 if (grfdebug & GDB_MMAP) 584 printf("grfmmap(%d): addr %x\n", p->p_pid, *addrp); 585 #endif 586 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize; 587 flags = MAP_FILE|MAP_SHARED; 588 if (*addrp) 589 flags |= MAP_FIXED; 590 else 591 *addrp = (caddr_t)0x1000000; /* XXX */ 592 vn.v_type = VCHR; /* XXX */ 593 vn.v_specinfo = &si; /* XXX */ 594 vn.v_rdev = dev; /* XXX */ 595 error = vm_mmap(u.u_procp->p_map, (vm_offset_t *)addrp, 596 (vm_size_t)len, VM_PROT_ALL, flags, (caddr_t)&vn, 0); 597 return(error); 598 } 599 600 grfunmmap(dev, addr) 601 dev_t dev; 602 caddr_t addr; 603 { 604 struct proc *p = u.u_procp; /* XXX */ 605 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 606 vm_size_t size; 607 int rv; 608 609 #ifdef DEBUG 610 if (grfdebug & GDB_MMAP) 611 printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr); 612 #endif 613 if (addr == 0) 614 return(EINVAL); /* XXX: how do we deal with this? */ 615 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize); 616 rv = vm_deallocate(p->p_map, (vm_offset_t)addr, size); 617 return(rv == KERN_SUCCESS ? 0 : EINVAL); 618 } 619 620 #ifdef HPUXCOMPAT 621 iommap(dev, addrp) 622 dev_t dev; 623 caddr_t *addrp; 624 { 625 struct proc *p = u.u_procp; /* XXX */ 626 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 627 628 #ifdef DEBUG 629 if (grfdebug & (GDB_MMAP|GDB_IOMAP)) 630 printf("iommap(%d): addr %x\n", p->p_pid, *addrp); 631 #endif 632 return(EINVAL); 633 } 634 635 iounmmap(dev, addr) 636 dev_t dev; 637 caddr_t addr; 638 { 639 int unit = minor(dev); 640 641 #ifdef DEBUG 642 if (grfdebug & (GDB_MMAP|GDB_IOMAP)) 643 printf("iounmmap(%d): id %d addr %x\n", 644 u.u_procp->p_pid, unit, addr); 645 #endif 646 return(0); 647 } 648 649 /* 650 * Processes involved in framebuffer mapping via GCSLOT are recorded in 651 * an array of pids. The first element is used to record the last slot used 652 * (for faster lookups). The remaining elements record up to GRFMAXLCK-1 653 * process ids. Returns a slot number between 1 and GRFMAXLCK or 0 if no 654 * slot is available. 655 */ 656 grffindpid(gp) 657 struct grf_softc *gp; 658 { 659 register short pid, *sp; 660 register int i, limit; 661 int ni; 662 663 if (gp->g_pid == NULL) { 664 gp->g_pid = (short *) 665 malloc(GRFMAXLCK * sizeof(short), M_DEVBUF, M_WAITOK); 666 bzero((caddr_t)gp->g_pid, GRFMAXLCK * sizeof(short)); 667 } 668 pid = u.u_procp->p_pid; 669 ni = limit = gp->g_pid[0]; 670 for (i = 1, sp = &gp->g_pid[1]; i <= limit; i++, sp++) { 671 if (*sp == pid) 672 goto done; 673 if (*sp == 0) 674 ni = i; 675 } 676 i = ni; 677 if (i < limit) { 678 gp->g_pid[i] = pid; 679 goto done; 680 } 681 if (++i == GRFMAXLCK) 682 return(0); 683 gp->g_pid[0] = i; 684 gp->g_pid[i] = pid; 685 done: 686 #ifdef DEBUG 687 if (grfdebug & GDB_LOCK) 688 printf("grffindpid(%d): slot %d of %d\n", 689 pid, i, gp->g_pid[0]); 690 #endif 691 return(i); 692 } 693 694 grfrmpid(gp) 695 struct grf_softc *gp; 696 { 697 register short pid, *sp; 698 register int limit, i; 699 int mi; 700 701 if (gp->g_pid == NULL || (limit = gp->g_pid[0]) == 0) 702 return; 703 pid = u.u_procp->p_pid; 704 limit = gp->g_pid[0]; 705 mi = 0; 706 for (i = 1, sp = &gp->g_pid[1]; i <= limit; i++, sp++) { 707 if (*sp == pid) 708 *sp = 0; 709 else if (*sp) 710 mi = i; 711 } 712 i = mi; 713 if (i < limit) 714 gp->g_pid[0] = i; 715 #ifdef DEBUG 716 if (grfdebug & GDB_LOCK) 717 printf("grfrmpid(%d): slot %d of %d\n", 718 pid, sp-gp->g_pid, gp->g_pid[0]); 719 #endif 720 } 721 722 grflckmmap(dev, addrp) 723 dev_t dev; 724 caddr_t *addrp; 725 { 726 struct proc *p = u.u_procp; /* XXX */ 727 728 #ifdef DEBUG 729 if (grfdebug & (GDB_MMAP|GDB_LOCK)) 730 printf("grflckmmap(%d): addr %x\n", 731 p->p_pid, *addrp); 732 #endif 733 return(EINVAL); 734 } 735 736 grflckunmmap(dev, addr) 737 dev_t dev; 738 caddr_t addr; 739 { 740 int unit = minor(dev); 741 742 #ifdef DEBUG 743 if (grfdebug & (GDB_MMAP|GDB_LOCK)) 744 printf("grflckunmmap(%d): id %d addr %x\n", 745 u.u_procp->p_pid, unit, addr); 746 #endif 747 return(EINVAL); 748 } 749 #endif /* HPUXCOMPAT */ 750 751 #endif /* NGRF > 0 */ 752