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