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.32 92/01/21$ 13 * 14 * @(#)grf.c 8.1 (Berkeley) 06/10/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 (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_md.md_flags & MDP_HPUX) 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_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, VM_PROT_ALL, 482 flags, (caddr_t)&vn, 0); 483 return(error); 484 } 485 486 grfunmmap(dev, addr, p) 487 dev_t dev; 488 caddr_t addr; 489 struct proc *p; 490 { 491 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 492 vm_size_t size; 493 int rv; 494 495 #ifdef DEBUG 496 if (grfdebug & GDB_MMAP) 497 printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr); 498 #endif 499 if (addr == 0) 500 return(EINVAL); /* XXX: how do we deal with this? */ 501 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize); 502 rv = vm_deallocate(&p->p_vmspace->vm_map, (vm_offset_t)addr, size); 503 return(rv == KERN_SUCCESS ? 0 : EINVAL); 504 } 505 506 #ifdef HPUXCOMPAT 507 iommap(dev, addrp) 508 dev_t dev; 509 caddr_t *addrp; 510 { 511 struct proc *p = curproc; /* XXX */ 512 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)]; 513 514 #ifdef DEBUG 515 if (grfdebug & (GDB_MMAP|GDB_IOMAP)) 516 printf("iommap(%d): addr %x\n", p->p_pid, *addrp); 517 #endif 518 return(EINVAL); 519 } 520 521 iounmmap(dev, addr) 522 dev_t dev; 523 caddr_t addr; 524 { 525 int unit = minor(dev); 526 527 #ifdef DEBUG 528 if (grfdebug & (GDB_MMAP|GDB_IOMAP)) 529 printf("iounmmap(%d): id %d addr %x\n", 530 curproc->p_pid, unit, addr); 531 #endif 532 return(0); 533 } 534 535 /* 536 * Processes involved in framebuffer mapping via GCSLOT are recorded in 537 * an array of pids. The first element is used to record the last slot used 538 * (for faster lookups). The remaining elements record up to GRFMAXLCK-1 539 * process ids. Returns a slot number between 1 and GRFMAXLCK or 0 if no 540 * slot is available. 541 */ 542 grffindpid(gp) 543 struct grf_softc *gp; 544 { 545 register short pid, *sp; 546 register int i, limit; 547 int ni; 548 549 if (gp->g_pid == NULL) { 550 gp->g_pid = (short *) 551 malloc(GRFMAXLCK * sizeof(short), M_DEVBUF, M_WAITOK); 552 bzero((caddr_t)gp->g_pid, GRFMAXLCK * sizeof(short)); 553 } 554 pid = curproc->p_pid; 555 ni = limit = gp->g_pid[0]; 556 for (i = 1, sp = &gp->g_pid[1]; i <= limit; i++, sp++) { 557 if (*sp == pid) 558 goto done; 559 if (*sp == 0) 560 ni = i; 561 } 562 i = ni; 563 if (i < limit) { 564 gp->g_pid[i] = pid; 565 goto done; 566 } 567 if (++i == GRFMAXLCK) 568 return(0); 569 gp->g_pid[0] = i; 570 gp->g_pid[i] = pid; 571 done: 572 #ifdef DEBUG 573 if (grfdebug & GDB_LOCK) 574 printf("grffindpid(%d): slot %d of %d\n", 575 pid, i, gp->g_pid[0]); 576 #endif 577 return(i); 578 } 579 580 grfrmpid(gp) 581 struct grf_softc *gp; 582 { 583 register short pid, *sp; 584 register int limit, i; 585 int mi; 586 587 if (gp->g_pid == NULL || (limit = gp->g_pid[0]) == 0) 588 return; 589 pid = curproc->p_pid; 590 limit = gp->g_pid[0]; 591 mi = 0; 592 for (i = 1, sp = &gp->g_pid[1]; i <= limit; i++, sp++) { 593 if (*sp == pid) 594 *sp = 0; 595 else if (*sp) 596 mi = i; 597 } 598 i = mi; 599 if (i < limit) 600 gp->g_pid[0] = i; 601 #ifdef DEBUG 602 if (grfdebug & GDB_LOCK) 603 printf("grfrmpid(%d): slot %d of %d\n", 604 pid, sp-gp->g_pid, gp->g_pid[0]); 605 #endif 606 } 607 608 grflckmmap(dev, addrp) 609 dev_t dev; 610 caddr_t *addrp; 611 { 612 #ifdef DEBUG 613 struct proc *p = curproc; /* XXX */ 614 615 if (grfdebug & (GDB_MMAP|GDB_LOCK)) 616 printf("grflckmmap(%d): addr %x\n", 617 p->p_pid, *addrp); 618 #endif 619 return(EINVAL); 620 } 621 622 grflckunmmap(dev, addr) 623 dev_t dev; 624 caddr_t addr; 625 { 626 #ifdef DEBUG 627 int unit = minor(dev); 628 629 if (grfdebug & (GDB_MMAP|GDB_LOCK)) 630 printf("grflckunmmap(%d): id %d addr %x\n", 631 curproc->p_pid, unit, addr); 632 #endif 633 return(EINVAL); 634 } 635 #endif /* HPUXCOMPAT */ 636 637 #endif /* NGRF > 0 */ 638