lint, cleanup
[unix-history] / usr / src / sys / hp / dev / grf.c
CommitLineData
60f56dfc
KM
1/*
2 * Copyright (c) 1988 University of Utah.
06b4439d
KB
3 * Copyright (c) 1990, 1993
4 * The Regents of the University of California. All rights reserved.
60f56dfc
KM
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 *
6e5e75f2 12 * from: Utah $Hdr: grf.c 1.36 93/08/13$
60f56dfc 13 *
2c0f281d 14 * @(#)grf.c 8.3 (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;
2c0f281d 70 int flags;
60f56dfc
KM
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 */
49b10dff 84 if (curproc->p_md.md_flags & MDP_HPUX)
60f56dfc
KM
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*/
108grfclose(dev, flags)
109 dev_t dev;
2c0f281d 110 int flags;
60f56dfc
KM
111{
112 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
113
114 (void) grfoff(dev);
6e5e75f2 115#ifdef HPUXCOMPAT
60f56dfc 116 (void) grfunlock(gp);
6e5e75f2 117#endif
60f56dfc
KM
118 gp->g_flags &= GF_ALIVE;
119 return(0);
120}
121
122/*ARGSUSED*/
88f29710 123grfioctl(dev, cmd, data, flag, p)
60f56dfc 124 dev_t dev;
2c0f281d 125 int cmd, flag;
60f56dfc 126 caddr_t data;
88f29710 127 struct proc *p;
60f56dfc
KM
128{
129 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
130 int error;
131
132#ifdef HPUXCOMPAT
49b10dff 133 if (p->p_md.md_flags & MDP_HPUX)
88f29710 134 return(hpuxgrfioctl(dev, cmd, data, flag, p));
60f56dfc
KM
135#endif
136 error = 0;
137 switch (cmd) {
138
60f56dfc
KM
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
60f56dfc 151 case GRFIOCMAP:
88f29710 152 error = grfmmap(dev, (caddr_t *)data, p);
60f56dfc
KM
153 break;
154
155 case GRFIOCUNMAP:
88f29710 156 error = grfunmmap(dev, *(caddr_t *)data, p);
60f56dfc 157 break;
60f56dfc
KM
158
159 default:
160 error = EINVAL;
161 break;
162
163 }
164 return(error);
165}
166
167/*ARGSUSED*/
168grfselect(dev, rw)
169 dev_t dev;
2c0f281d 170 int rw;
60f56dfc
KM
171{
172 if (rw == FREAD)
173 return(0);
174 return(1);
175}
176
6e5e75f2
MH
177/*ARGSUSED*/
178grfmap(dev, off, prot)
179 dev_t dev;
2c0f281d 180 int off, prot;
60f56dfc 181{
6e5e75f2 182 return(grfaddr(&grf_softc[GRFUNIT(dev)], off));
60f56dfc
KM
183}
184
6e5e75f2
MH
185grfon(dev)
186 dev_t dev;
60f56dfc 187{
6e5e75f2
MH
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));
60f56dfc
KM
200}
201
6e5e75f2 202grfoff(dev)
60f56dfc
KM
203 dev_t dev;
204{
6e5e75f2
MH
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
218grfaddr(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);
60f56dfc
KM
235}
236
6e5e75f2
MH
237/*
238 * HP-UX compatibility routines
239 */
60f56dfc
KM
240#ifdef HPUXCOMPAT
241
242/*ARGSUSED*/
88f29710 243hpuxgrfioctl(dev, cmd, data, flag, p)
60f56dfc 244 dev_t dev;
2c0f281d 245 int cmd, flag;
60f56dfc 246 caddr_t data;
88f29710 247 struct proc *p;
60f56dfc
KM
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
60f56dfc
KM
284 /* map in control regs and frame buffer */
285 case GCMAP:
88f29710 286 error = grfmmap(dev, (caddr_t *)data, p);
60f56dfc
KM
287 break;
288
289 case GCUNMAP:
88f29710 290 error = grfunmmap(dev, *(caddr_t *)data, p);
60f56dfc
KM
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);
22d09b27 301 if (sp->slot) {
60f56dfc 302 error = grflckmmap(dev, (caddr_t *)&sp->addr);
22d09b27
KM
303 if (error && gp->g_pid) {
304 free((caddr_t)gp->g_pid, M_DEVBUF);
305 gp->g_pid = NULL;
306 }
307 } else
60f56dfc
KM
308 error = EINVAL; /* XXX */
309 break;
310 }
311
6e5e75f2
MH
312 case GCDESCRIBE:
313 error = (*gp->g_sw->gd_mode)(gp, GM_DESCRIBE, data);
314 break;
315
60f56dfc
KM
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);
96d5f73d
MH
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 */
60f56dfc
KM
330 if (!error)
331 u.u_r.r_val1 = *(int *)data; /* XXX: this sux */
96d5f73d 332#endif
60f56dfc
KM
333 break;
334
335 case IOMAPUNMAP:
336 error = iounmmap(dev, *(caddr_t *)data);
337 break;
60f56dfc
KM
338
339 default:
340 error = EINVAL;
341 break;
342 }
343 return(error);
344}
345
6e5e75f2
MH
346grflock(gp, block)
347 register struct grf_softc *gp;
348 int block;
60f56dfc 349{
6e5e75f2 350 struct proc *p = curproc; /* XXX */
60f56dfc 351 int error;
6e5e75f2 352 extern char devioc[];
60f56dfc 353
6e5e75f2
MH
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);
60f56dfc
KM
397}
398
6e5e75f2
MH
399grfunlock(gp)
400 register struct grf_softc *gp;
60f56dfc 401{
6e5e75f2
MH
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;
60f56dfc 419 }
6e5e75f2
MH
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);
60f56dfc
KM
426}
427
60f56dfc
KM
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 */
435grfdevno(dev)
436 dev_t dev;
437{
438 int unit = GRFUNIT(dev);
439 struct grf_softc *gp = &grf_softc[unit];
7b7da76f 440 int newdev;
60f56dfc
KM
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 */
950dea01 447 if (gp->g_display.gd_regaddr != (caddr_t)GRFIADDR) {
7b7da76f 448 int sc = patosc(gp->g_display.gd_regaddr);
950dea01
MH
449 newdev |= (sc << 16) | 0x200;
450 }
60f56dfc
KM
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}
6e5e75f2
MH
461
462#endif /* HPUXCOMPAT */
60f56dfc 463
88f29710 464grfmmap(dev, addrp, p)
60f56dfc
KM
465 dev_t dev;
466 caddr_t *addrp;
88f29710 467 struct proc *p;
60f56dfc
KM
468{
469 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
22d09b27
KM
470 int len, error;
471 struct vnode vn;
472 struct specinfo si;
473 int flags;
60f56dfc
KM
474
475#ifdef DEBUG
476 if (grfdebug & GDB_MMAP)
05d14dfb 477 printf("grfmmap(%d): addr %x\n", p->p_pid, *addrp);
60f56dfc
KM
478#endif
479 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize;
a24ecba5 480 flags = MAP_SHARED;
22d09b27
KM
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 */
88f29710 488 error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp,
1990cc1d
MH
489 (vm_size_t)len, VM_PROT_ALL, VM_PROT_ALL,
490 flags, (caddr_t)&vn, 0);
6e5e75f2
MH
491 if (error == 0)
492 (void) (*gp->g_sw->gd_mode)(gp, GM_MAP, *addrp);
96d5f73d 493 return(error);
60f56dfc
KM
494}
495
88f29710 496grfunmmap(dev, addr, p)
60f56dfc
KM
497 dev_t dev;
498 caddr_t addr;
88f29710 499 struct proc *p;
60f56dfc 500{
22d09b27
KM
501 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
502 vm_size_t size;
503 int rv;
60f56dfc
KM
504
505#ifdef DEBUG
506 if (grfdebug & GDB_MMAP)
22d09b27 507 printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr);
60f56dfc 508#endif
22d09b27
KM
509 if (addr == 0)
510 return(EINVAL); /* XXX: how do we deal with this? */
6e5e75f2 511 (void) (*gp->g_sw->gd_mode)(gp, GM_UNMAP, 0);
22d09b27 512 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize);
6055b25f 513 rv = vm_deallocate(&p->p_vmspace->vm_map, (vm_offset_t)addr, size);
22d09b27 514 return(rv == KERN_SUCCESS ? 0 : EINVAL);
60f56dfc
KM
515}
516
517#ifdef HPUXCOMPAT
518iommap(dev, addrp)
519 dev_t dev;
520 caddr_t *addrp;
521{
88f29710 522 struct proc *p = curproc; /* XXX */
60f56dfc 523 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
60f56dfc
KM
524
525#ifdef DEBUG
526 if (grfdebug & (GDB_MMAP|GDB_IOMAP))
05d14dfb 527 printf("iommap(%d): addr %x\n", p->p_pid, *addrp);
60f56dfc 528#endif
22d09b27 529 return(EINVAL);
60f56dfc
KM
530}
531
532iounmmap(dev, addr)
533 dev_t dev;
534 caddr_t addr;
535{
22d09b27 536 int unit = minor(dev);
60f56dfc
KM
537
538#ifdef DEBUG
539 if (grfdebug & (GDB_MMAP|GDB_IOMAP))
540 printf("iounmmap(%d): id %d addr %x\n",
88f29710 541 curproc->p_pid, unit, addr);
60f56dfc 542#endif
22d09b27 543 return(0);
60f56dfc
KM
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 */
553grffindpid(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 }
88f29710 565 pid = curproc->p_pid;
60f56dfc
KM
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;
582done:
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
591grfrmpid(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;
88f29710 600 pid = curproc->p_pid;
60f56dfc
KM
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
60f56dfc
KM
619grflckmmap(dev, addrp)
620 dev_t dev;
621 caddr_t *addrp;
622{
60f56dfc 623#ifdef DEBUG
88f29710
MK
624 struct proc *p = curproc; /* XXX */
625
60f56dfc
KM
626 if (grfdebug & (GDB_MMAP|GDB_LOCK))
627 printf("grflckmmap(%d): addr %x\n",
05d14dfb 628 p->p_pid, *addrp);
60f56dfc 629#endif
22d09b27 630 return(EINVAL);
60f56dfc
KM
631}
632
633grflckunmmap(dev, addr)
634 dev_t dev;
635 caddr_t addr;
636{
88f29710 637#ifdef DEBUG
60f56dfc
KM
638 int unit = minor(dev);
639
60f56dfc
KM
640 if (grfdebug & (GDB_MMAP|GDB_LOCK))
641 printf("grflckunmmap(%d): id %d addr %x\n",
88f29710 642 curproc->p_pid, unit, addr);
60f56dfc 643#endif
60f56dfc
KM
644 return(EINVAL);
645}
646#endif /* HPUXCOMPAT */
22d09b27 647
60f56dfc 648#endif /* NGRF > 0 */