grf.c revision 1.9
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 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * from: Utah $Hdr: grf.c 1.31 91/01/21$
39 *
40 *	@(#)grf.c	7.8 (Berkeley) 5/7/91
41 *	$Id: grf.c,v 1.9 1994/02/17 09:10:32 chopps Exp $
42 */
43
44/*
45 * Graphics display driver for the AMIGA
46 * This is the hardware-independent portion of the driver.
47 * Hardware access is through the grfdev routines below.
48 */
49
50#include "grf.h"
51#if NGRF > 0
52
53#include <sys/param.h>
54#include <sys/proc.h>
55#include <sys/ioctl.h>
56#include <sys/file.h>
57#include <sys/malloc.h>
58#include <sys/conf.h>
59#include <sys/systm.h>
60
61#include <amiga/dev/device.h>
62#include <amiga/dev/grfioctl.h>
63#include <amiga/dev/grfvar.h>
64
65#include <machine/cpu.h>
66
67#include <vm/vm.h>
68#include <vm/vm_kern.h>
69#include <vm/vm_page.h>
70#include <vm/vm_pager.h>
71
72#include <miscfs/specfs/specdev.h>
73#include <sys/vnode.h>
74#include <sys/mman.h>
75
76#if defined (__STDC__)
77#define GET_CHRDEV_MAJOR(dev, maj) { \
78	for(maj = 0; maj < nchrdev; maj++) \
79		if (cdevsw[maj].d_open == dev ## open) \
80			break; \
81}
82#else
83#define GET_CHRDEV_MAJOR(dev, maj) { \
84	for(maj = 0; maj < nchrdev; maj++) \
85		if (cdevsw[maj].d_open == dev/**/open) \
86			break; \
87}
88#endif
89
90#include "ite.h"
91#if NITE == 0
92#define	ite_on(u,f)
93#define	ite_off(u,f)
94#define ite_reinit(d)
95#endif
96
97int	grfprobe();
98int	cc_init(), cc_mode();
99int	tg_init(), tg_mode();
100int	rt_init(), rt_mode();
101
102struct grfdev grfdev[] = {
103	MANUF_BUILTIN,		PROD_BUILTIN_DISPLAY,
104		cc_init,  cc_mode,  "custom chips",
105	MANUF_UNILOWELL,	PROD_UNILOWELL_A2410,
106		tg_init,  tg_mode,    "A2410 TIGA",
107	MANUF_MACROSYSTEM,	PROD_MACROSYSTEM_RETINA,
108		rt_init,  rt_mode,    "Retina",
109};
110int	ngrfdev = sizeof(grfdev) / sizeof(grfdev[0]);
111
112struct	driver grfdriver = { grfprobe, "grf" };
113struct	grf_softc grf_softc[NGRF];
114
115#ifdef DEBUG
116int grfdebug = 0;
117#define GDB_DEVNO	0x01
118#define GDB_MMAP	0x02
119#define GDB_IOMAP	0x04
120#define GDB_LOCK	0x08
121#endif
122
123/*
124 * XXX: called from ite console init routine.
125 * Does just what configure will do later but without printing anything.
126 */
127grfconfig()
128{
129	register caddr_t addr;
130	register struct amiga_hw *hw;
131	register struct amiga_device *ad, *nad;
132
133	for (hw = sc_table; hw->hw_type; hw++) {
134	        if (!HW_ISDEV(hw, D_BITMAP))
135			continue;
136		/*
137		 * Found one, now match up with a logical unit number
138		 */
139		nad = NULL;
140		addr = hw->hw_kva;
141		for (ad = amiga_dinit; ad->amiga_driver; ad++) {
142			if (ad->amiga_driver != &grfdriver || ad->amiga_alive)
143				continue;
144			/*
145			 * Wildcarded.  If first, remember as possible match.
146			 */
147			if (ad->amiga_addr == NULL) {
148				if (nad == NULL)
149					nad = ad;
150				continue;
151			}
152			/*
153			 * Not wildcarded.
154			 * If exact match done searching, else keep looking.
155			 */
156			if (((hw->hw_manufacturer << 16) | hw->hw_product)
157			    == (u_int) ad->amiga_addr) {
158				nad = ad;
159				break;
160			}
161		}
162		/*
163		 * Found a match, initialize
164		 */
165		if (nad && grfinit (nad, hw))
166		  nad->amiga_addr = addr;
167	}
168}
169
170/*
171 * Normal init routine called by configure() code
172 */
173grfprobe(ad)
174	struct amiga_device *ad;
175{
176	struct grf_softc *gp = &grf_softc[ad->amiga_unit];
177
178	/* can't reinit, as ad->amiga_addr no longer contains
179	   manuf/prod information */
180	if ((gp->g_flags & GF_ALIVE) == 0 /* &&
181	    !grfinit (ad) */)
182		return(0);
183	printf("grf%d: %d x %d ", ad->amiga_unit,
184	       gp->g_display.gd_dwidth, gp->g_display.gd_dheight);
185	if (gp->g_display.gd_colors == 2)
186		printf("monochrome");
187	else
188		printf("%d color", gp->g_display.gd_colors);
189	printf(" %s display\n", grfdev[gp->g_type].gd_desc);
190	return(1);
191}
192
193grfinit(ad, ahw)
194	struct amiga_device *ad;
195	struct amiga_hw *ahw;
196{
197	struct grf_softc *gp = &grf_softc[ad->amiga_unit];
198	register struct grfdev *gd;
199
200	for (gd = grfdev; gd < &grfdev[ngrfdev]; gd++)
201	  if (((gd->gd_manuf << 16) | gd->gd_prod) == (u_int)ad->amiga_addr)
202	    break;
203
204	if (gd < &grfdev[ngrfdev] && (*gd->gd_init)(gp, ad, ahw)) {
205		gp->g_type = gd - grfdev;
206		gp->g_flags = GF_ALIVE;
207		return(1);
208	}
209	return(0);
210}
211
212/*ARGSUSED*/
213grfopen(dev, flags)
214	dev_t dev;
215{
216	int unit = GRFUNIT(dev);
217	register struct grf_softc *gp = &grf_softc[unit];
218	int error = 0;
219
220	if (unit >= NGRF || (gp->g_flags & GF_ALIVE) == 0)
221		return(ENXIO);
222	if ((gp->g_flags & (GF_OPEN|GF_EXCLUDE)) == (GF_OPEN|GF_EXCLUDE))
223		return(EBUSY);
224#if 0
225	/*
226	 * First open.
227	 * XXX: always put in graphics mode.
228	 */
229	error = 0;
230	if ((gp->g_flags & GF_OPEN) == 0) {
231		gp->g_flags |= GF_OPEN;
232		error = grfon(dev);
233	}
234#endif
235	return(error);
236}
237
238/*ARGSUSED*/
239grfclose(dev, flags)
240	dev_t dev;
241{
242	register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
243
244	(void) grfoff(dev);
245	(void) grfunlock(gp);
246	gp->g_flags &= GF_ALIVE;
247	return(0);
248}
249
250/*ARGSUSED*/
251grfioctl(dev, cmd, data, flag, p)
252	dev_t dev;
253	caddr_t data;
254	struct proc *p;
255{
256	register struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
257	int error;
258
259	error = 0;
260	switch (cmd) {
261
262	case OGRFIOCGINFO:
263	        /* argl.. no bank-member.. */
264	  	bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo)-4);
265		break;
266
267	case GRFIOCGINFO:
268		bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo));
269		break;
270
271	case GRFIOCON:
272		error = grfon(dev);
273		break;
274
275	case GRFIOCOFF:
276		error = grfoff(dev);
277		break;
278
279	case GRFIOCMAP:
280		error = grfmmap(dev, (caddr_t *)data, p);
281		break;
282
283	case GRFIOCUNMAP:
284		error = grfunmmap(dev, *(caddr_t *)data, p);
285		break;
286
287	case GRFIOCSINFO:
288		error = grfsinfo (dev, (struct grfdyninfo *) data);
289		break;
290
291	case GRFGETVMODE:
292		return grfdev[gp->g_type].gd_mode (gp, GM_GRFGETVMODE, data);
293
294	case GRFSETVMODE:
295		error = grfdev[gp->g_type].gd_mode (gp, GM_GRFSETVMODE, data);
296		if (! error)
297		  {
298		    /* XXX */
299		    ite_reinit (GRFUNIT (dev));
300		  }
301		break;
302
303	case GRFGETNUMVM:
304		return grfdev[gp->g_type].gd_mode (gp, GM_GRFGETNUMVM, data);
305
306		/* these are all hardware dependant, and have to be resolved
307		   in the respective driver. */
308	case GRFIOCPUTCMAP:
309	case GRFIOCGETCMAP:
310	case GRFIOCSSPRITEPOS:
311	case GRFIOCGSPRITEPOS:
312	case GRFIOCSSPRITEINF:
313	case GRFIOCGSPRITEINF:
314	case GRFIOCGSPRITEMAX:
315		return grfdev[gp->g_type].gd_mode (gp, GM_GRFIOCTL, cmd, data);
316
317	default:
318		/* check to see whether it's a command recognized by the
319		   view code if the unit is 0 XXX */
320		if (GRFUNIT(dev) == 0)
321		  return viewioctl (dev, cmd, data, flag, p);
322		error = EINVAL;
323		break;
324
325	}
326	return(error);
327}
328
329/*ARGSUSED*/
330grfselect(dev, rw)
331	dev_t dev;
332{
333	if (rw == FREAD)
334		return(0);
335	return(1);
336}
337
338grflock(gp, block)
339	register struct grf_softc *gp;
340	int block;
341{
342	struct proc *p = curproc;		/* XXX */
343	int error;
344	extern char devioc[];
345
346#ifdef DEBUG
347	if (grfdebug & GDB_LOCK)
348		printf("grflock(%d): dev %x flags %x lockpid %x\n",
349		       p->p_pid, gp-grf_softc, gp->g_flags,
350		       gp->g_lockp ? gp->g_lockp->p_pid : -1);
351#endif
352	if (gp->g_lockp) {
353		if (gp->g_lockp == p)
354			return(EBUSY);
355		if (!block)
356			return(EAGAIN);
357		do {
358			gp->g_flags |= GF_WANTED;
359			if (error = tsleep((caddr_t)&gp->g_flags,
360					   (PZERO+1) | PCATCH, devioc, 0))
361				return (error);
362		} while (gp->g_lockp);
363	}
364	gp->g_lockp = p;
365	return(0);
366}
367
368grfunlock(gp)
369	register struct grf_softc *gp;
370{
371#ifdef DEBUG
372	if (grfdebug & GDB_LOCK)
373		printf("grfunlock(%d): dev %x flags %x lockpid %d\n",
374		       curproc->p_pid, gp-grf_softc, gp->g_flags,
375		       gp->g_lockp ? gp->g_lockp->p_pid : -1);
376#endif
377	if (gp->g_lockp != curproc)
378		return(EBUSY);
379	if (gp->g_flags & GF_WANTED) {
380		wakeup((caddr_t)&gp->g_flags);
381		gp->g_flags &= ~GF_WANTED;
382	}
383	gp->g_lockp = NULL;
384	return(0);
385}
386
387/*ARGSUSED*/
388grfmap(dev, off, prot)
389	dev_t dev;
390{
391	return(grfaddr(&grf_softc[GRFUNIT(dev)], off));
392}
393
394grfon(dev)
395	dev_t dev;
396{
397	extern int iteopen __P((dev_t, int, int, struct proc *));
398	int maj;
399	int unit = GRFUNIT(dev);
400	struct grf_softc *gp = &grf_softc[unit];
401
402	if (gp->g_flags & GF_GRFON)
403	  return 0;
404	gp->g_flags |= GF_GRFON;
405
406	/* XXX relies on the unit matching */
407	GET_CHRDEV_MAJOR(ite, maj);
408	ite_off(makedev(maj,unit), 3);
409	return((*grfdev[gp->g_type].gd_mode)
410			(gp, (dev&GRFOVDEV) ? GM_GRFOVON : GM_GRFON));
411}
412
413grfoff(dev)
414	dev_t dev;
415{
416	extern int iteopen __P((dev_t, int, int, struct proc *));
417	int maj;
418	int unit = GRFUNIT(dev);
419	struct grf_softc *gp = &grf_softc[unit];
420	int error;
421
422	if (!(gp->g_flags & GF_GRFON))
423	  return 0;
424	gp->g_flags &= ~GF_GRFON;
425
426	(void) grfunmmap(dev, (caddr_t)0, curproc);
427	error = (*grfdev[gp->g_type].gd_mode)
428			(gp, (dev&GRFOVDEV) ? GM_GRFOVOFF : GM_GRFOFF);
429	/* XXX relies on the unit matching */
430	GET_CHRDEV_MAJOR(ite, maj);
431	ite_on(makedev(maj,unit), 2);
432	return(error);
433}
434
435grfsinfo(dev, dyninfo)
436	dev_t dev;
437	struct grfdyninfo *dyninfo;
438{
439	int unit = GRFUNIT(dev);
440	struct grf_softc *gp = &grf_softc[unit];
441	int error;
442
443	error = grfdev[gp->g_type].gd_mode (gp, GM_GRFCONFIG, dyninfo);
444	/* XXX: see comment for iteoff above */
445	ite_reinit (unit);
446	return(error);
447}
448
449grfaddr(gp, off)
450	struct grf_softc *gp;
451	register int off;
452{
453	register struct grfinfo *gi = &gp->g_display;
454
455	/* control registers */
456	if (off >= 0 && off < gi->gd_regsize)
457		return(((u_int)gi->gd_regaddr + off) >> PGSHIFT);
458
459	/* frame buffer */
460	if (off >= gi->gd_regsize && off < gi->gd_regsize+gi->gd_fbsize) {
461		off -= gi->gd_regsize;
462#ifdef BANKEDDEVPAGER
463		if (gi->gd_bank_size)
464		  off %= gi->gd_bank_size;
465#endif
466		return(((u_int)gi->gd_fbaddr + off) >> PGSHIFT);
467	}
468	/* bogus */
469	return(-1);
470}
471
472grfmmap(dev, addrp, p)
473	dev_t dev;
474	caddr_t *addrp;
475	struct proc *p;
476{
477	struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
478	int len, error;
479	struct vnode vn;
480	struct specinfo si;
481	int flags;
482
483#ifdef DEBUG
484	if (grfdebug & GDB_MMAP)
485		printf("grfmmap(%d): addr %x\n", p->p_pid, *addrp);
486#endif
487	len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize;
488	flags = MAP_FILE|MAP_SHARED;
489	if (*addrp)
490		flags |= MAP_FIXED;
491	else {
492		/*
493		 * XXX if no hint provided for a non-fixed mapping place it after
494		 * the end of the largest possible heap.
495		 *
496		 * There should really be a pmap call to determine a reasonable
497		 * location.
498		 */
499		*addrp = (caddr_t) round_page(p->p_vmspace->vm_daddr + MAXDSIZ);
500	}
501	bzero (&vn, sizeof (vn));
502	bzero (&si, sizeof (si));
503	vn.v_type = VCHR;			/* XXX */
504	vn.v_specinfo = &si;			/* XXX */
505	vn.v_rdev = dev;			/* XXX */
506  	error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp,
507			(vm_size_t)len, VM_PROT_ALL, VM_PROT_ALL, flags,
508			(caddr_t)&vn, 0);
509	return(error);
510}
511
512grfunmmap(dev, addr, p)
513	dev_t dev;
514	caddr_t addr;
515	struct proc *p;
516{
517	struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
518	vm_size_t size;
519	int rv;
520
521#ifdef DEBUG
522	if (grfdebug & GDB_MMAP)
523		printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr);
524#endif
525	if (addr == 0)
526		return(EINVAL);		/* XXX: how do we deal with this? */
527	size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize);
528	rv = vm_deallocate(p->p_vmspace->vm_map, (vm_offset_t)addr, size);
529	return(rv == KERN_SUCCESS ? 0 : EINVAL);
530}
531
532#ifdef BANKEDDEVPAGER
533
534int
535grfbanked_get (dev, off, prot)
536     dev_t dev;
537     off_t off;
538     int   prot;
539{
540  int unit = GRFUNIT(dev);
541  struct grf_softc *gp = &grf_softc[unit];
542  int error, bank;
543  struct grfinfo *gi = &gp->g_display;
544
545  off -= gi->gd_regsize;
546  if (off < 0 || off >= gi->gd_fbsize)
547    return -1;
548
549  error = grfdev[gp->g_type].gd_mode (gp, GM_GRFGETBANK, &bank, off, prot);
550  return error ? -1 : bank;
551}
552
553int
554grfbanked_cur (dev)
555     dev_t dev;
556{
557  int unit = GRFUNIT(dev);
558  struct grf_softc *gp = &grf_softc[unit];
559  int error, bank;
560
561  error = grfdev[gp->g_type].gd_mode (gp, GM_GRFGETCURBANK, &bank);
562  return error ? -1 : bank;
563}
564
565int
566grfbanked_set (dev, bank)
567     dev_t dev;
568     int bank;
569{
570  int unit = GRFUNIT(dev);
571  struct grf_softc *gp = &grf_softc[unit];
572
573  return grfdev[gp->g_type].gd_mode (gp, GM_GRFSETBANK, bank) ? -1 : 0;
574}
575
576#endif /* BANKEDDEVPAGER */
577
578#endif	/* NGRF > 0 */
579