strategy returns void, ioctl cmd is u_long
[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 *
053d16fe 14 * @(#)grf.c 8.5 (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;
053d16fe 125 u_long cmd;
60f56dfc 126 caddr_t data;
053d16fe 127 int flag;
88f29710 128 struct proc *p;
60f56dfc
KM
129{
130 register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
131 int error;
132
133#ifdef HPUXCOMPAT
49b10dff 134 if (p->p_md.md_flags & MDP_HPUX)
88f29710 135 return(hpuxgrfioctl(dev, cmd, data, flag, p));
60f56dfc
KM
136#endif
137 error = 0;
138 switch (cmd) {
139
60f56dfc
KM
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
60f56dfc 152 case GRFIOCMAP:
88f29710 153 error = grfmmap(dev, (caddr_t *)data, p);
60f56dfc
KM
154 break;
155
156 case GRFIOCUNMAP:
88f29710 157 error = grfunmmap(dev, *(caddr_t *)data, p);
60f56dfc 158 break;
60f56dfc
KM
159
160 default:
161 error = EINVAL;
162 break;
163
164 }
165 return(error);
166}
167
168/*ARGSUSED*/
169grfselect(dev, rw)
170 dev_t dev;
2c0f281d 171 int rw;
60f56dfc
KM
172{
173 if (rw == FREAD)
174 return(0);
175 return(1);
176}
177
6e5e75f2
MH
178/*ARGSUSED*/
179grfmap(dev, off, prot)
180 dev_t dev;
2c0f281d 181 int off, prot;
60f56dfc 182{
6e5e75f2 183 return(grfaddr(&grf_softc[GRFUNIT(dev)], off));
60f56dfc
KM
184}
185
6e5e75f2
MH
186grfon(dev)
187 dev_t dev;
60f56dfc 188{
6e5e75f2
MH
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));
60f56dfc
KM
201}
202
6e5e75f2 203grfoff(dev)
60f56dfc
KM
204 dev_t dev;
205{
6e5e75f2
MH
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
219grfaddr(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);
60f56dfc
KM
236}
237
6e5e75f2
MH
238/*
239 * HP-UX compatibility routines
240 */
60f56dfc
KM
241#ifdef HPUXCOMPAT
242
243/*ARGSUSED*/
88f29710 244hpuxgrfioctl(dev, cmd, data, flag, p)
60f56dfc 245 dev_t dev;
053d16fe 246 u_long cmd;
60f56dfc 247 caddr_t data;
053d16fe 248 int flag;
88f29710 249 struct proc *p;
60f56dfc
KM
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
60f56dfc
KM
286 /* map in control regs and frame buffer */
287 case GCMAP:
88f29710 288 error = grfmmap(dev, (caddr_t *)data, p);
60f56dfc
KM
289 break;
290
291 case GCUNMAP:
88f29710 292 error = grfunmmap(dev, *(caddr_t *)data, p);
60f56dfc
KM
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);
22d09b27 303 if (sp->slot) {
60f56dfc 304 error = grflckmmap(dev, (caddr_t *)&sp->addr);
22d09b27
KM
305 if (error && gp->g_pid) {
306 free((caddr_t)gp->g_pid, M_DEVBUF);
307 gp->g_pid = NULL;
308 }
309 } else
60f56dfc
KM
310 error = EINVAL; /* XXX */
311 break;
312 }
313
6e5e75f2
MH
314 case GCDESCRIBE:
315 error = (*gp->g_sw->gd_mode)(gp, GM_DESCRIBE, data);
316 break;
317
60f56dfc
KM
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);
96d5f73d
MH
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 */
60f56dfc
KM
332 if (!error)
333 u.u_r.r_val1 = *(int *)data; /* XXX: this sux */
96d5f73d 334#endif
60f56dfc
KM
335 break;
336
337 case IOMAPUNMAP:
338 error = iounmmap(dev, *(caddr_t *)data);
339 break;
60f56dfc
KM
340
341 default:
342 error = EINVAL;
343 break;
344 }
345 return(error);
346}
347
6e5e75f2
MH
348grflock(gp, block)
349 register struct grf_softc *gp;
350 int block;
60f56dfc 351{
6e5e75f2 352 struct proc *p = curproc; /* XXX */
60f56dfc 353 int error;
6e5e75f2 354 extern char devioc[];
60f56dfc 355
6e5e75f2
MH
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);
60f56dfc
KM
399}
400
6e5e75f2
MH
401grfunlock(gp)
402 register struct grf_softc *gp;
60f56dfc 403{
6e5e75f2
MH
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;
60f56dfc 421 }
6e5e75f2
MH
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);
60f56dfc
KM
428}
429
60f56dfc
KM
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 */
437grfdevno(dev)
438 dev_t dev;
439{
440 int unit = GRFUNIT(dev);
441 struct grf_softc *gp = &grf_softc[unit];
7b7da76f 442 int newdev;
60f56dfc
KM
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 */
950dea01 449 if (gp->g_display.gd_regaddr != (caddr_t)GRFIADDR) {
7b7da76f 450 int sc = patosc(gp->g_display.gd_regaddr);
950dea01
MH
451 newdev |= (sc << 16) | 0x200;
452 }
60f56dfc
KM
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}
6e5e75f2
MH
463
464#endif /* HPUXCOMPAT */
60f56dfc 465
88f29710 466grfmmap(dev, addrp, p)
60f56dfc
KM
467 dev_t dev;
468 caddr_t *addrp;
88f29710 469 struct proc *p;
60f56dfc
KM
470{
471 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
22d09b27
KM
472 int len, error;
473 struct vnode vn;
474 struct specinfo si;
475 int flags;
60f56dfc
KM
476
477#ifdef DEBUG
478 if (grfdebug & GDB_MMAP)
05d14dfb 479 printf("grfmmap(%d): addr %x\n", p->p_pid, *addrp);
60f56dfc
KM
480#endif
481 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize;
a24ecba5 482 flags = MAP_SHARED;
22d09b27
KM
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 */
88f29710 490 error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp,
1990cc1d
MH
491 (vm_size_t)len, VM_PROT_ALL, VM_PROT_ALL,
492 flags, (caddr_t)&vn, 0);
6e5e75f2
MH
493 if (error == 0)
494 (void) (*gp->g_sw->gd_mode)(gp, GM_MAP, *addrp);
96d5f73d 495 return(error);
60f56dfc
KM
496}
497
88f29710 498grfunmmap(dev, addr, p)
60f56dfc
KM
499 dev_t dev;
500 caddr_t addr;
88f29710 501 struct proc *p;
60f56dfc 502{
22d09b27
KM
503 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
504 vm_size_t size;
505 int rv;
60f56dfc
KM
506
507#ifdef DEBUG
508 if (grfdebug & GDB_MMAP)
22d09b27 509 printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr);
60f56dfc 510#endif
22d09b27
KM
511 if (addr == 0)
512 return(EINVAL); /* XXX: how do we deal with this? */
6e5e75f2 513 (void) (*gp->g_sw->gd_mode)(gp, GM_UNMAP, 0);
22d09b27 514 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize);
6055b25f 515 rv = vm_deallocate(&p->p_vmspace->vm_map, (vm_offset_t)addr, size);
22d09b27 516 return(rv == KERN_SUCCESS ? 0 : EINVAL);
60f56dfc
KM
517}
518
519#ifdef HPUXCOMPAT
520iommap(dev, addrp)
521 dev_t dev;
522 caddr_t *addrp;
523{
60f56dfc
KM
524
525#ifdef DEBUG
526 if (grfdebug & (GDB_MMAP|GDB_IOMAP))
8a6691f4 527 printf("iommap(%d): addr %x\n", curproc->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 */