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