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.32 92/01/21$ 13 * 14 * @(#)grf.c 7.11 (Berkeley) 06/05/92 15 */ 16 17 /* 18 * Graphics display driver for HP 300/400/700/800 machines. 19 * This is the hardware-independent portion of the driver. 20 * Hardware access is through the machine dependent grf switch routines. 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 "grfioctl.h" 33 #include "grfvar.h" 34 #include "grfreg.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 "vnode.h" 48 #include "specdev.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 struct grf_softc grf_softc[NGRF]; 58 59 #ifdef DEBUG 60 int grfdebug = 0; 61 #define GDB_DEVNO 0x01 62 #define GDB_MMAP 0x02 63 #define GDB_IOMAP 0x04 64 #define GDB_LOCK 0x08 65 #endif 66 67 /*ARGSUSED*/ 68 grfopen(dev, flags) 69 dev_t dev; 70 { 71 int unit = GRFUNIT(dev); 72 register struct grf_softc *gp = &grf_softc[unit]; 73 int error = 0; 74 75 if (unit >= NGRF || (gp->g_flags & GF_ALIVE) == 0) 76 return(ENXIO); 77 if ((gp->g_flags & (GF_OPEN|GF_EXCLUDE)) == (GF_OPEN|GF_EXCLUDE)) 78 return(EBUSY); 79 #ifdef HPUXCOMPAT 80 /* 81 * XXX: cannot handle both HPUX and BSD processes at the same time 82 */ 83 if (curproc->p_flag & SHPUX) 84 if (gp->g_flags & GF_BSDOPEN) 85 return(EBUSY); 86 else 87 gp->g_flags |= GF_HPUXOPEN; 88 else 89 if (gp->g_flags & GF_HPUXOPEN) 90 return(EBUSY); 91 else 92 gp->g_flags |= GF_BSDOPEN; 93 #endif 94 /* 95 * First open. 96 * XXX: always put in graphics mode. 97 */ 98 error = 0; 99 if ((gp->g_flags & GF_OPEN) == 0) { 100 gp->g_flags |= GF_OPEN; 101 error = grfon(dev); 102 } 103 return(error); 104 } 105 106 /*ARGSUSED*/ 107 grfclose(dev, flags) 108 dev_t dev; 109 { 110 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 111 112 (void) grfoff(dev); 113 (void) grfunlock(gp); 114 gp->g_flags &= GF_ALIVE; 115 return(0); 116 } 117 118 /*ARGSUSED*/ 119 grfioctl(dev, cmd, data, flag, p) 120 dev_t dev; 121 caddr_t data; 122 struct proc *p; 123 { 124 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 125 int error; 126 127 #ifdef HPUXCOMPAT 128 if (p->p_flag & SHPUX) 129 return(hpuxgrfioctl(dev, cmd, data, flag, p)); 130 #endif 131 error = 0; 132 switch (cmd) { 133 134 case GRFIOCGINFO: 135 bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo)); 136 break; 137 138 case GRFIOCON: 139 error = grfon(dev); 140 break; 141 142 case GRFIOCOFF: 143 error = grfoff(dev); 144 break; 145 146 case GRFIOCMAP: 147 error = grfmmap(dev, (caddr_t *)data, p); 148 break; 149 150 case GRFIOCUNMAP: 151 error = grfunmmap(dev, *(caddr_t *)data, p); 152 break; 153 154 default: 155 error = EINVAL; 156 break; 157 158 } 159 return(error); 160 } 161 162 /*ARGSUSED*/ 163 grfselect(dev, rw) 164 dev_t dev; 165 { 166 if (rw == FREAD) 167 return(0); 168 return(1); 169 } 170 171 grflock(gp, block) 172 register struct grf_softc *gp; 173 int block; 174 { 175 struct proc *p = curproc; /* XXX */ 176 int error; 177 extern char devioc[]; 178 179 #ifdef DEBUG 180 if (grfdebug & GDB_LOCK) 181 printf("grflock(%d): dev %x flags %x lockpid %x\n", 182 p->p_pid, gp-grf_softc, gp->g_flags, 183 gp->g_lockp ? gp->g_lockp->p_pid : -1); 184 #endif 185 #ifdef HPUXCOMPAT 186 if (gp->g_pid) { 187 #ifdef DEBUG 188 if (grfdebug & GDB_LOCK) 189 printf(" lockpslot %d lockslot %d lock[lockslot] %d\n", 190 gp->g_lock->gl_lockslot, gp->g_lockpslot, 191 gp->g_lock->gl_locks[gp->g_lockpslot]); 192 #endif 193 gp->g_lock->gl_lockslot = 0; 194 if (gp->g_lock->gl_locks[gp->g_lockpslot] == 0) { 195 gp->g_lockp = NULL; 196 gp->g_lockpslot = 0; 197 } 198 } 199 #endif 200 if (gp->g_lockp) { 201 if (gp->g_lockp == p) 202 return(EBUSY); 203 if (!block) 204 return(EAGAIN); 205 do { 206 gp->g_flags |= GF_WANTED; 207 if (error = tsleep((caddr_t)&gp->g_flags, 208 (PZERO+1) | PCATCH, devioc, 0)) 209 return (error); 210 } while (gp->g_lockp); 211 } 212 gp->g_lockp = p; 213 #ifdef HPUXCOMPAT 214 if (gp->g_pid) { 215 int slot = grffindpid(gp); 216 #ifdef DEBUG 217 if (grfdebug & GDB_LOCK) 218 printf(" slot %d\n", slot); 219 #endif 220 gp->g_lockpslot = gp->g_lock->gl_lockslot = slot; 221 gp->g_lock->gl_locks[slot] = 1; 222 } 223 #endif 224 return(0); 225 } 226 227 grfunlock(gp) 228 register struct grf_softc *gp; 229 { 230 #ifdef DEBUG 231 if (grfdebug & GDB_LOCK) 232 printf("grfunlock(%d): dev %x flags %x lockpid %d\n", 233 curproc->p_pid, gp-grf_softc, gp->g_flags, 234 gp->g_lockp ? gp->g_lockp->p_pid : -1); 235 #endif 236 if (gp->g_lockp != curproc) 237 return(EBUSY); 238 #ifdef HPUXCOMPAT 239 if (gp->g_pid) { 240 #ifdef DEBUG 241 if (grfdebug & GDB_LOCK) 242 printf(" lockpslot %d lockslot %d lock[lockslot] %d\n", 243 gp->g_lock->gl_lockslot, gp->g_lockpslot, 244 gp->g_lock->gl_locks[gp->g_lockpslot]); 245 #endif 246 gp->g_lock->gl_locks[gp->g_lockpslot] = 0; 247 gp->g_lockpslot = gp->g_lock->gl_lockslot = 0; 248 } 249 #endif 250 if (gp->g_flags & GF_WANTED) { 251 wakeup((caddr_t)&gp->g_flags); 252 gp->g_flags &= ~GF_WANTED; 253 } 254 gp->g_lockp = NULL; 255 return(0); 256 } 257 258 /*ARGSUSED*/ 259 grfmap(dev, off, prot) 260 dev_t dev; 261 { 262 return(grfaddr(&grf_softc[GRFUNIT(dev)], off)); 263 } 264 265 #ifdef HPUXCOMPAT 266 267 /*ARGSUSED*/ 268 hpuxgrfioctl(dev, cmd, data, flag, p) 269 dev_t dev; 270 caddr_t data; 271 struct proc *p; 272 { 273 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 274 int error; 275 276 error = 0; 277 switch (cmd) { 278 279 case GCID: 280 *(int *)data = gp->g_display.gd_id; 281 break; 282 283 case GCON: 284 error = grfon(dev); 285 break; 286 287 case GCOFF: 288 error = grfoff(dev); 289 break; 290 291 case GCLOCK: 292 error = grflock(gp, 1); 293 break; 294 295 case GCUNLOCK: 296 error = grfunlock(gp); 297 break; 298 299 case GCAON: 300 case GCAOFF: 301 break; 302 303 /* GCSTATIC is implied by our implementation */ 304 case GCSTATIC_CMAP: 305 case GCVARIABLE_CMAP: 306 break; 307 308 /* map in control regs and frame buffer */ 309 case GCMAP: 310 error = grfmmap(dev, (caddr_t *)data, p); 311 break; 312 313 case GCUNMAP: 314 error = grfunmmap(dev, *(caddr_t *)data, p); 315 /* XXX: HP-UX uses GCUNMAP to get rid of GCSLOT memory */ 316 if (error) 317 error = grflckunmmap(dev, *(caddr_t *)data); 318 break; 319 320 case GCSLOT: 321 { 322 struct grf_slot *sp = (struct grf_slot *)data; 323 324 sp->slot = grffindpid(gp); 325 if (sp->slot) { 326 error = grflckmmap(dev, (caddr_t *)&sp->addr); 327 if (error && gp->g_pid) { 328 free((caddr_t)gp->g_pid, M_DEVBUF); 329 gp->g_pid = NULL; 330 } 331 } else 332 error = EINVAL; /* XXX */ 333 break; 334 } 335 336 /* 337 * XXX: only used right now to map in rbox control registers 338 * Will be replaced in the future with a real IOMAP interface. 339 */ 340 case IOMAPMAP: 341 error = iommap(dev, (caddr_t *)data); 342 #if 0 343 /* 344 * It may not be worth kludging this (using p_devtmp) to 345 * make this work. It was an undocumented side-effect 346 * in HP-UX that the mapped address was the return value 347 * of the ioctl. The only thing I remember that counted 348 * on this behavior was the rbox X10 server. 349 */ 350 if (!error) 351 u.u_r.r_val1 = *(int *)data; /* XXX: this sux */ 352 #endif 353 break; 354 355 case IOMAPUNMAP: 356 error = iounmmap(dev, *(caddr_t *)data); 357 break; 358 359 default: 360 error = EINVAL; 361 break; 362 } 363 return(error); 364 } 365 366 #endif 367 368 grfon(dev) 369 dev_t dev; 370 { 371 int unit = GRFUNIT(dev); 372 struct grf_softc *gp = &grf_softc[unit]; 373 374 /* 375 * XXX: iteoff call relies on devices being in same order 376 * as ITEs and the fact that iteoff only uses the minor part 377 * of the dev arg. 378 */ 379 iteoff(unit, 3); 380 return((*gp->g_sw->gd_mode)(gp, 381 (dev&GRFOVDEV) ? GM_GRFOVON : GM_GRFON, 382 (caddr_t)0)); 383 } 384 385 grfoff(dev) 386 dev_t dev; 387 { 388 int unit = GRFUNIT(dev); 389 struct grf_softc *gp = &grf_softc[unit]; 390 int error; 391 392 (void) grfunmmap(dev, (caddr_t)0, curproc); 393 error = (*gp->g_sw->gd_mode)(gp, 394 (dev&GRFOVDEV) ? GM_GRFOVOFF : GM_GRFOFF, 395 (caddr_t)0); 396 /* XXX: see comment for iteoff above */ 397 iteon(unit, 2); 398 return(error); 399 } 400 401 grfaddr(gp, off) 402 struct grf_softc *gp; 403 register int off; 404 { 405 register struct grfinfo *gi = &gp->g_display; 406 407 /* control registers */ 408 if (off >= 0 && off < gi->gd_regsize) 409 return(((u_int)gi->gd_regaddr + off) >> PGSHIFT); 410 411 /* frame buffer */ 412 if (off >= gi->gd_regsize && off < gi->gd_regsize+gi->gd_fbsize) { 413 off -= gi->gd_regsize; 414 return(((u_int)gi->gd_fbaddr + off) >> PGSHIFT); 415 } 416 /* bogus */ 417 return(-1); 418 } 419 420 #ifdef HPUXCOMPAT 421 /* 422 * Convert a BSD style minor devno to HPUX style. 423 * We cannot just create HPUX style nodes as they require 24 bits 424 * of minor device number and we only have 8. 425 * XXX: This may give the wrong result for remote stats of other 426 * machines where device 10 exists. 427 */ 428 grfdevno(dev) 429 dev_t dev; 430 { 431 int unit = GRFUNIT(dev); 432 struct grf_softc *gp = &grf_softc[unit]; 433 int newdev; 434 435 if (unit >= NGRF || (gp->g_flags&GF_ALIVE) == 0) 436 return(bsdtohpuxdev(dev)); 437 /* magic major number */ 438 newdev = 12 << 24; 439 /* now construct minor number */ 440 if (gp->g_display.gd_regaddr != (caddr_t)GRFIADDR) { 441 int sc = patosc(gp->g_display.gd_regaddr); 442 newdev |= (sc << 16) | 0x200; 443 } 444 if (dev & GRFIMDEV) 445 newdev |= 0x02; 446 else if (dev & GRFOVDEV) 447 newdev |= 0x01; 448 #ifdef DEBUG 449 if (grfdebug & GDB_DEVNO) 450 printf("grfdevno: dev %x newdev %x\n", dev, newdev); 451 #endif 452 return(newdev); 453 } 454 #endif 455 456 grfmmap(dev, addrp, p) 457 dev_t dev; 458 caddr_t *addrp; 459 struct proc *p; 460 { 461 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 462 int len, error; 463 struct vnode vn; 464 struct specinfo si; 465 int flags; 466 467 #ifdef DEBUG 468 if (grfdebug & GDB_MMAP) 469 printf("grfmmap(%d): addr %x\n", p->p_pid, *addrp); 470 #endif 471 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize; 472 flags = MAP_FILE|MAP_SHARED; 473 if (*addrp) 474 flags |= MAP_FIXED; 475 else 476 *addrp = (caddr_t)0x1000000; /* XXX */ 477 vn.v_type = VCHR; /* XXX */ 478 vn.v_specinfo = &si; /* XXX */ 479 vn.v_rdev = dev; /* XXX */ 480 error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp, 481 (vm_size_t)len, VM_PROT_ALL, flags, (caddr_t)&vn, 0); 482 return(error); 483 } 484 485 grfunmmap(dev, addr, p) 486 dev_t dev; 487 caddr_t addr; 488 struct proc *p; 489 { 490 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 491 vm_size_t size; 492 int rv; 493 494 #ifdef DEBUG 495 if (grfdebug & GDB_MMAP) 496 printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr); 497 #endif 498 if (addr == 0) 499 return(EINVAL); /* XXX: how do we deal with this? */ 500 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize); 501 rv = vm_deallocate(&p->p_vmspace->vm_map, (vm_offset_t)addr, size); 502 return(rv == KERN_SUCCESS ? 0 : EINVAL); 503 } 504 505 #ifdef HPUXCOMPAT 506 iommap(dev, addrp) 507 dev_t dev; 508 caddr_t *addrp; 509 { 510 struct proc *p = curproc; /* XXX */ 511 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 512 513 #ifdef DEBUG 514 if (grfdebug & (GDB_MMAP|GDB_IOMAP)) 515 printf("iommap(%d): addr %x\n", p->p_pid, *addrp); 516 #endif 517 return(EINVAL); 518 } 519 520 iounmmap(dev, addr) 521 dev_t dev; 522 caddr_t addr; 523 { 524 int unit = minor(dev); 525 526 #ifdef DEBUG 527 if (grfdebug & (GDB_MMAP|GDB_IOMAP)) 528 printf("iounmmap(%d): id %d addr %x\n", 529 curproc->p_pid, unit, addr); 530 #endif 531 return(0); 532 } 533 534 /* 535 * Processes involved in framebuffer mapping via GCSLOT are recorded in 536 * an array of pids. The first element is used to record the last slot used 537 * (for faster lookups). The remaining elements record up to GRFMAXLCK-1 538 * process ids. Returns a slot number between 1 and GRFMAXLCK or 0 if no 539 * slot is available. 540 */ 541 grffindpid(gp) 542 struct grf_softc *gp; 543 { 544 register short pid, *sp; 545 register int i, limit; 546 int ni; 547 548 if (gp->g_pid == NULL) { 549 gp->g_pid = (short *) 550 malloc(GRFMAXLCK * sizeof(short), M_DEVBUF, M_WAITOK); 551 bzero((caddr_t)gp->g_pid, GRFMAXLCK * sizeof(short)); 552 } 553 pid = curproc->p_pid; 554 ni = limit = gp->g_pid[0]; 555 for (i = 1, sp = &gp->g_pid[1]; i <= limit; i++, sp++) { 556 if (*sp == pid) 557 goto done; 558 if (*sp == 0) 559 ni = i; 560 } 561 i = ni; 562 if (i < limit) { 563 gp->g_pid[i] = pid; 564 goto done; 565 } 566 if (++i == GRFMAXLCK) 567 return(0); 568 gp->g_pid[0] = i; 569 gp->g_pid[i] = pid; 570 done: 571 #ifdef DEBUG 572 if (grfdebug & GDB_LOCK) 573 printf("grffindpid(%d): slot %d of %d\n", 574 pid, i, gp->g_pid[0]); 575 #endif 576 return(i); 577 } 578 579 grfrmpid(gp) 580 struct grf_softc *gp; 581 { 582 register short pid, *sp; 583 register int limit, i; 584 int mi; 585 586 if (gp->g_pid == NULL || (limit = gp->g_pid[0]) == 0) 587 return; 588 pid = curproc->p_pid; 589 limit = gp->g_pid[0]; 590 mi = 0; 591 for (i = 1, sp = &gp->g_pid[1]; i <= limit; i++, sp++) { 592 if (*sp == pid) 593 *sp = 0; 594 else if (*sp) 595 mi = i; 596 } 597 i = mi; 598 if (i < limit) 599 gp->g_pid[0] = i; 600 #ifdef DEBUG 601 if (grfdebug & GDB_LOCK) 602 printf("grfrmpid(%d): slot %d of %d\n", 603 pid, sp-gp->g_pid, gp->g_pid[0]); 604 #endif 605 } 606 607 grflckmmap(dev, addrp) 608 dev_t dev; 609 caddr_t *addrp; 610 { 611 #ifdef DEBUG 612 struct proc *p = curproc; /* XXX */ 613 614 if (grfdebug & (GDB_MMAP|GDB_LOCK)) 615 printf("grflckmmap(%d): addr %x\n", 616 p->p_pid, *addrp); 617 #endif 618 return(EINVAL); 619 } 620 621 grflckunmmap(dev, addr) 622 dev_t dev; 623 caddr_t addr; 624 { 625 #ifdef DEBUG 626 int unit = minor(dev); 627 628 if (grfdebug & (GDB_MMAP|GDB_LOCK)) 629 printf("grflckunmmap(%d): id %d addr %x\n", 630 curproc->p_pid, unit, addr); 631 #endif 632 return(EINVAL); 633 } 634 #endif /* HPUXCOMPAT */ 635 636 #endif /* NGRF > 0 */ 637