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