grf.c revision 1.4 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 "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
79 int grfprobe();
80 int cc_init(), cc_mode();
81 int tg_init(), tg_mode();
82 int rt_init(), rt_mode();
83
84 struct 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 };
92 int ngrfdev = sizeof(grfdev) / sizeof(grfdev[0]);
93
94 struct driver grfdriver = { grfprobe, "grf" };
95 struct grf_softc grf_softc[NGRF];
96
97 #ifdef DEBUG
98 int 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 */
109 grfconfig()
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 == 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 */
155 grfprobe(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
175 grfinit(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) == 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*/
195 grfopen(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*/
221 grfclose(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*/
233 grfioctl(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 GRFIOCGINFO:
245 bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo));
246 break;
247
248 case GRFIOCON:
249 error = grfon(dev);
250 break;
251
252 case GRFIOCOFF:
253 error = grfoff(dev);
254 break;
255
256 case GRFIOCMAP:
257 error = grfmmap(dev, (caddr_t *)data, p);
258 break;
259
260 case GRFIOCUNMAP:
261 error = grfunmmap(dev, *(caddr_t *)data, p);
262 break;
263
264 case GRFIOCSINFO:
265 error = grfsinfo (dev, (struct grfdyninfo *) data);
266 break;
267
268 case GRFGETVMODE:
269 return grfdev[gp->g_type].gd_mode (gp, GM_GRFGETVMODE, data);
270
271 case GRFSETVMODE:
272 error = grfdev[gp->g_type].gd_mode (gp, GM_GRFSETVMODE, data);
273 if (! error)
274 {
275 /* XXX */
276 itereinit (GRFUNIT (dev));
277 }
278 break;
279
280 case GRFGETNUMVM:
281 return grfdev[gp->g_type].gd_mode (gp, GM_GRFGETNUMVM, data);
282
283 default:
284 error = EINVAL;
285 break;
286
287 }
288 return(error);
289 }
290
291 /*ARGSUSED*/
292 grfselect(dev, rw)
293 dev_t dev;
294 {
295 if (rw == FREAD)
296 return(0);
297 return(1);
298 }
299
300 grflock(gp, block)
301 register struct grf_softc *gp;
302 int block;
303 {
304 struct proc *p = curproc; /* XXX */
305 int error;
306 extern char devioc[];
307
308 #ifdef DEBUG
309 if (grfdebug & GDB_LOCK)
310 printf("grflock(%d): dev %x flags %x lockpid %x\n",
311 p->p_pid, gp-grf_softc, gp->g_flags,
312 gp->g_lockp ? gp->g_lockp->p_pid : -1);
313 #endif
314 if (gp->g_lockp) {
315 if (gp->g_lockp == p)
316 return(EBUSY);
317 if (!block)
318 return(EAGAIN);
319 do {
320 gp->g_flags |= GF_WANTED;
321 if (error = tsleep((caddr_t)&gp->g_flags,
322 (PZERO+1) | PCATCH, devioc, 0))
323 return (error);
324 } while (gp->g_lockp);
325 }
326 gp->g_lockp = p;
327 return(0);
328 }
329
330 grfunlock(gp)
331 register struct grf_softc *gp;
332 {
333 #ifdef DEBUG
334 if (grfdebug & GDB_LOCK)
335 printf("grfunlock(%d): dev %x flags %x lockpid %d\n",
336 curproc->p_pid, gp-grf_softc, gp->g_flags,
337 gp->g_lockp ? gp->g_lockp->p_pid : -1);
338 #endif
339 if (gp->g_lockp != curproc)
340 return(EBUSY);
341 if (gp->g_flags & GF_WANTED) {
342 wakeup((caddr_t)&gp->g_flags);
343 gp->g_flags &= ~GF_WANTED;
344 }
345 gp->g_lockp = NULL;
346 return(0);
347 }
348
349 /*ARGSUSED*/
350 grfmap(dev, off, prot)
351 dev_t dev;
352 {
353 return(grfaddr(&grf_softc[GRFUNIT(dev)], off));
354 }
355
356
357 grfon(dev)
358 dev_t dev;
359 {
360 int unit = GRFUNIT(dev);
361 struct grf_softc *gp = &grf_softc[unit];
362
363 if (gp->g_flags & GF_GRFON)
364 return 0;
365 gp->g_flags |= GF_GRFON;
366
367 /*
368 * XXX: iteoff call relies on devices being in same order
369 * as ITEs and the fact that iteoff only uses the minor part
370 * of the dev arg.
371 */
372 iteoff(unit, 3);
373 return((*grfdev[gp->g_type].gd_mode)
374 (gp, (dev&GRFOVDEV) ? GM_GRFOVON : GM_GRFON));
375 }
376
377 grfoff(dev)
378 dev_t dev;
379 {
380 int unit = GRFUNIT(dev);
381 struct grf_softc *gp = &grf_softc[unit];
382 int error;
383
384 if (!(gp->g_flags & GF_GRFON))
385 return 0;
386 gp->g_flags &= ~GF_GRFON;
387
388 (void) grfunmmap(dev, (caddr_t)0, curproc);
389 error = (*grfdev[gp->g_type].gd_mode)
390 (gp, (dev&GRFOVDEV) ? GM_GRFOVOFF : GM_GRFOFF);
391 /* XXX: see comment for iteoff above */
392 iteon(unit, 2);
393 return(error);
394 }
395
396 grfsinfo(dev, dyninfo)
397 dev_t dev;
398 struct grfdyninfo *dyninfo;
399 {
400 int unit = GRFUNIT(dev);
401 struct grf_softc *gp = &grf_softc[unit];
402 int error;
403
404 error = grfdev[gp->g_type].gd_mode (gp, GM_GRFCONFIG, dyninfo);
405 /* XXX: see comment for iteoff above */
406 itereinit (unit);
407 return(error);
408 }
409
410 grfaddr(gp, off)
411 struct grf_softc *gp;
412 register int off;
413 {
414 register struct grfinfo *gi = &gp->g_display;
415
416 /* control registers */
417 if (off >= 0 && off < gi->gd_regsize)
418 return(((u_int)gi->gd_regaddr + off) >> PGSHIFT);
419
420 /* frame buffer */
421 if (off >= gi->gd_regsize && off < gi->gd_regsize+gi->gd_fbsize) {
422 off -= gi->gd_regsize;
423 return(((u_int)gi->gd_fbaddr + off) >> PGSHIFT);
424 }
425 /* bogus */
426 return(-1);
427 }
428
429 grfmmap(dev, addrp, p)
430 dev_t dev;
431 caddr_t *addrp;
432 struct proc *p;
433 {
434 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
435 int len, error;
436 struct vnode vn;
437 struct specinfo si;
438 int flags;
439
440 #ifdef DEBUG
441 if (grfdebug & GDB_MMAP)
442 printf("grfmmap(%d): addr %x\n", p->p_pid, *addrp);
443 #endif
444 len = gp->g_display.gd_regsize + gp->g_display.gd_fbsize;
445 flags = MAP_FILE|MAP_SHARED;
446 if (*addrp)
447 flags |= MAP_FIXED;
448 else
449 *addrp = (caddr_t)0x1000000; /* XXX */
450 vn.v_type = VCHR; /* XXX */
451 vn.v_specinfo = &si; /* XXX */
452 vn.v_rdev = dev; /* XXX */
453 error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp,
454 (vm_size_t)len, VM_PROT_ALL, VM_PROT_ALL, flags,
455 (caddr_t)&vn, 0);
456 return(error);
457 }
458
459 grfunmmap(dev, addr, p)
460 dev_t dev;
461 caddr_t addr;
462 struct proc *p;
463 {
464 struct grf_softc *gp = &grf_softc[GRFUNIT(dev)];
465 vm_size_t size;
466 int rv;
467
468 #ifdef DEBUG
469 if (grfdebug & GDB_MMAP)
470 printf("grfunmmap(%d): dev %x addr %x\n", p->p_pid, dev, addr);
471 #endif
472 if (addr == 0)
473 return(EINVAL); /* XXX: how do we deal with this? */
474 size = round_page(gp->g_display.gd_regsize + gp->g_display.gd_fbsize);
475 rv = vm_deallocate(p->p_vmspace->vm_map, (vm_offset_t)addr, size);
476 return(rv == KERN_SUCCESS ? 0 : EINVAL);
477 }
478
479
480 #endif /* NGRF > 0 */
481