4.4BSD snapshot (revision 8.1)
[unix-history] / usr / src / sys / hp / dev / grf.c
CommitLineData
60f56dfc
KM
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 *
7b7da76f 12 * from: Utah $Hdr: grf.c 1.32 92/01/21$
60f56dfc 13 *
1990cc1d 14 * @(#)grf.c 7.16 (Berkeley) %G%
60f56dfc
KM
15 */
16
17/*
7b7da76f 18 * Graphics display driver for HP 300/400/700/800 machines.
60f56dfc 19 * This is the hardware-independent portion of the driver.
7b7da76f 20 * Hardware access is through the machine dependent grf switch routines.
60f56dfc
KM
21 */
22
38a01dbe 23#include "grf.h"
60f56dfc
KM
24#if NGRF > 0
25
bc22c9dd
KM
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>
60f56dfc 33
bc22c9dd
KM
34#include <hp/dev/grfioctl.h>
35#include <hp/dev/grfvar.h>
36#include <hp/dev/grfreg.h>
60f56dfc 37
bc22c9dd 38#include <machine/cpu.h>
60f56dfc
KM
39
40#ifdef HPUXCOMPAT
bc22c9dd 41#include <hp/hpux/hpux.h>
60f56dfc
KM
42#endif
43
bc22c9dd
KM
44#include <vm/vm.h>
45#include <vm/vm_kern.h>
46#include <vm/vm_page.h>
47#include <vm/vm_pager.h>
88f29710 48
bc22c9dd 49#include <miscfs/specfs/specdev.h>
22d09b27 50
bc22c9dd 51#include <ite.h>
60f56dfc
KM
52#if NITE == 0
53#define iteon(u,f)
54#define iteoff(u,f)
55#endif
56
60f56dfc
KM
57struct grf_softc grf_softc[NGRF];
58
60f56dfc
KM
59#ifdef DEBUG
60int 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
60f56dfc
KM
67/*ARGSUSED*/
68grfopen(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 */
49b10dff 83 if (curproc->p_md.md_flags & MDP_HPUX)
60f56dfc
KM
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*/
107grfclose(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*/
88f29710 119grfioctl(dev, cmd, data, flag, p)
60f56dfc
KM
120 dev_t dev;
121 caddr_t data;
88f29710 122 struct proc *p;
60f56dfc
KM
123{
124 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
125 int error;
126
127#ifdef HPUXCOMPAT
49b10dff 128 if (p->p_md.md_flags & MDP_HPUX)
88f29710 129 return(hpuxgrfioctl(dev, cmd, data, flag, p));
60f56dfc
KM
130#endif
131 error = 0;
132 switch (cmd) {
133
60f56dfc
KM
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
60f56dfc 146 case GRFIOCMAP:
88f29710 147 error = grfmmap(dev, (caddr_t *)data, p);
60f56dfc
KM
148 break;
149
150 case GRFIOCUNMAP:
88f29710 151 error = grfunmmap(dev, *(caddr_t *)data, p);
60f56dfc 152 break;
60f56dfc
KM
153
154 default:
155 error = EINVAL;
156 break;
157
158 }
159 return(error);
160}
161
162/*ARGSUSED*/
163grfselect(dev, rw)
164 dev_t dev;
165{
166 if (rw == FREAD)
167 return(0);
168 return(1);
169}
170
171grflock(gp, block)
172 register struct grf_softc *gp;
173 int block;
174{
88f29710 175 struct proc *p = curproc; /* XXX */
339a5f2c
KM
176 int error;
177 extern char devioc[];
178
60f56dfc
KM
179#ifdef DEBUG
180 if (grfdebug & GDB_LOCK)
181 printf("grflock(%d): dev %x flags %x lockpid %x\n",
05d14dfb 182 p->p_pid, gp-grf_softc, gp->g_flags,
60f56dfc
KM
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)
950dea01
MH
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]);
60f56dfc 192#endif
950dea01
MH
193 gp->g_lock->gl_lockslot = 0;
194 if (gp->g_lock->gl_locks[gp->g_lockpslot] == 0) {
60f56dfc
KM
195 gp->g_lockp = NULL;
196 gp->g_lockpslot = 0;
197 }
198 }
199#endif
200 if (gp->g_lockp) {
05d14dfb 201 if (gp->g_lockp == p)
60f56dfc
KM
202 return(EBUSY);
203 if (!block)
204 return(EAGAIN);
205 do {
206 gp->g_flags |= GF_WANTED;
339a5f2c
KM
207 if (error = tsleep((caddr_t)&gp->g_flags,
208 (PZERO+1) | PCATCH, devioc, 0))
209 return (error);
60f56dfc
KM
210 } while (gp->g_lockp);
211 }
05d14dfb 212 gp->g_lockp = p;
60f56dfc
KM
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
950dea01
MH
220 gp->g_lockpslot = gp->g_lock->gl_lockslot = slot;
221 gp->g_lock->gl_locks[slot] = 1;
60f56dfc
KM
222 }
223#endif
224 return(0);
225}
226
227grfunlock(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",
88f29710 233 curproc->p_pid, gp-grf_softc, gp->g_flags,
60f56dfc
KM
234 gp->g_lockp ? gp->g_lockp->p_pid : -1);
235#endif
88f29710 236 if (gp->g_lockp != curproc)
60f56dfc
KM
237 return(EBUSY);
238#ifdef HPUXCOMPAT
239 if (gp->g_pid) {
240#ifdef DEBUG
241 if (grfdebug & GDB_LOCK)
950dea01
MH
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]);
60f56dfc 245#endif
950dea01
MH
246 gp->g_lock->gl_locks[gp->g_lockpslot] = 0;
247 gp->g_lockpslot = gp->g_lock->gl_lockslot = 0;
60f56dfc
KM
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*/
259grfmap(dev, off, prot)
260 dev_t dev;
261{
262 return(grfaddr(&grf_softc[GRFUNIT(dev)], off));
263}
264
265#ifdef HPUXCOMPAT
266
267/*ARGSUSED*/
88f29710 268hpuxgrfioctl(dev, cmd, data, flag, p)
60f56dfc
KM
269 dev_t dev;
270 caddr_t data;
88f29710 271 struct proc *p;
60f56dfc
KM
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
60f56dfc
KM
308 /* map in control regs and frame buffer */
309 case GCMAP:
88f29710 310 error = grfmmap(dev, (caddr_t *)data, p);
60f56dfc
KM
311 break;
312
313 case GCUNMAP:
88f29710 314 error = grfunmmap(dev, *(caddr_t *)data, p);
60f56dfc
KM
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);
22d09b27 325 if (sp->slot) {
60f56dfc 326 error = grflckmmap(dev, (caddr_t *)&sp->addr);
22d09b27
KM
327 if (error && gp->g_pid) {
328 free((caddr_t)gp->g_pid, M_DEVBUF);
329 gp->g_pid = NULL;
330 }
331 } else
60f56dfc
KM
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);
96d5f73d
MH
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 */
60f56dfc
KM
350 if (!error)
351 u.u_r.r_val1 = *(int *)data; /* XXX: this sux */
96d5f73d 352#endif
60f56dfc
KM
353 break;
354
355 case IOMAPUNMAP:
356 error = iounmmap(dev, *(caddr_t *)data);
357 break;
60f56dfc
KM
358
359 default:
360 error = EINVAL;
361 break;
362 }
363 return(error);
364}
365
366#endif
367
368grfon(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);
7b7da76f
MH
380 return((*gp->g_sw->gd_mode)(gp,
381 (dev&GRFOVDEV) ? GM_GRFOVON : GM_GRFON,
382 (caddr_t)0));
60f56dfc
KM
383}
384
385grfoff(dev)
386 dev_t dev;
387{
388 int unit = GRFUNIT(dev);
389 struct grf_softc *gp = &grf_softc[unit];
390 int error;
391
88f29710 392 (void) grfunmmap(dev, (caddr_t)0, curproc);
7b7da76f
MH
393 error = (*gp->g_sw->gd_mode)(gp,
394 (dev&GRFOVDEV) ? GM_GRFOVOFF : GM_GRFOFF,
395 (caddr_t)0);
60f56dfc
KM
396 /* XXX: see comment for iteoff above */
397 iteon(unit, 2);
398 return(error);
399}
400
401grfaddr(gp, off)
402 struct grf_softc *gp;
403 register int off;
404{
60f56dfc
KM
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 }
60f56dfc
KM
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 */
428grfdevno(dev)
429 dev_t dev;
430{
431 int unit = GRFUNIT(dev);
432 struct grf_softc *gp = &grf_softc[unit];
7b7da76f 433 int newdev;
60f56dfc
KM
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 */
950dea01 440 if (gp->g_display.gd_regaddr != (caddr_t)GRFIADDR) {
7b7da76f 441 int sc = patosc(gp->g_display.gd_regaddr);
950dea01
MH
442 newdev |= (sc << 16) | 0x200;
443 }
60f56dfc
KM
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
88f29710 456grfmmap(dev, addrp, p)
60f56dfc
KM
457 dev_t dev;
458 caddr_t *addrp;
88f29710 459 struct proc *p;
60f56dfc
KM
460{
461 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
22d09b27
KM
462 int len, error;
463 struct vnode vn;
464 struct specinfo si;
465 int flags;
60f56dfc
KM
466
467#ifdef DEBUG
468 if (grfdebug & GDB_MMAP)
05d14dfb 469 printf("grfmmap(%d): addr %x\n", p->p_pid, *addrp);
60f56dfc
KM
470#endif
471 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize;
a24ecba5 472 flags = MAP_SHARED;
22d09b27
KM
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 */
88f29710 480 error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp,
1990cc1d
MH
481 (vm_size_t)len, VM_PROT_ALL, VM_PROT_ALL,
482 flags, (caddr_t)&vn, 0);
96d5f73d 483 return(error);
60f56dfc
KM
484}
485
88f29710 486grfunmmap(dev, addr, p)
60f56dfc
KM
487 dev_t dev;
488 caddr_t addr;
88f29710 489 struct proc *p;
60f56dfc 490{
22d09b27
KM
491 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
492 vm_size_t size;
493 int rv;
60f56dfc
KM
494
495#ifdef DEBUG
496 if (grfdebug & GDB_MMAP)
22d09b27 497 printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr);
60f56dfc 498#endif
22d09b27
KM
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);
6055b25f 502 rv = vm_deallocate(&p->p_vmspace->vm_map, (vm_offset_t)addr, size);
22d09b27 503 return(rv == KERN_SUCCESS ? 0 : EINVAL);
60f56dfc
KM
504}
505
506#ifdef HPUXCOMPAT
507iommap(dev, addrp)
508 dev_t dev;
509 caddr_t *addrp;
510{
88f29710 511 struct proc *p = curproc; /* XXX */
60f56dfc 512 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
60f56dfc
KM
513
514#ifdef DEBUG
515 if (grfdebug & (GDB_MMAP|GDB_IOMAP))
05d14dfb 516 printf("iommap(%d): addr %x\n", p->p_pid, *addrp);
60f56dfc 517#endif
22d09b27 518 return(EINVAL);
60f56dfc
KM
519}
520
521iounmmap(dev, addr)
522 dev_t dev;
523 caddr_t addr;
524{
22d09b27 525 int unit = minor(dev);
60f56dfc
KM
526
527#ifdef DEBUG
528 if (grfdebug & (GDB_MMAP|GDB_IOMAP))
529 printf("iounmmap(%d): id %d addr %x\n",
88f29710 530 curproc->p_pid, unit, addr);
60f56dfc 531#endif
22d09b27 532 return(0);
60f56dfc
KM
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 */
542grffindpid(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 }
88f29710 554 pid = curproc->p_pid;
60f56dfc
KM
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;
571done:
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
580grfrmpid(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;
88f29710 589 pid = curproc->p_pid;
60f56dfc
KM
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
60f56dfc
KM
608grflckmmap(dev, addrp)
609 dev_t dev;
610 caddr_t *addrp;
611{
60f56dfc 612#ifdef DEBUG
88f29710
MK
613 struct proc *p = curproc; /* XXX */
614
60f56dfc
KM
615 if (grfdebug & (GDB_MMAP|GDB_LOCK))
616 printf("grflckmmap(%d): addr %x\n",
05d14dfb 617 p->p_pid, *addrp);
60f56dfc 618#endif
22d09b27 619 return(EINVAL);
60f56dfc
KM
620}
621
622grflckunmmap(dev, addr)
623 dev_t dev;
624 caddr_t addr;
625{
88f29710 626#ifdef DEBUG
60f56dfc
KM
627 int unit = minor(dev);
628
60f56dfc
KM
629 if (grfdebug & (GDB_MMAP|GDB_LOCK))
630 printf("grflckunmmap(%d): id %d addr %x\n",
88f29710 631 curproc->p_pid, unit, addr);
60f56dfc 632#endif
60f56dfc
KM
633 return(EINVAL);
634}
635#endif /* HPUXCOMPAT */
22d09b27 636
60f56dfc 637#endif /* NGRF > 0 */