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