grf.c revision 1.5 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
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 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*/
312 grfselect(dev, rw)
313 dev_t dev;
314 {
315 if (rw == FREAD)
316 return(0);
317 return(1);
318 }
319
320 grflock(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
350 grfunlock(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*/
370 grfmap(dev, off, prot)
371 dev_t dev;
372 {
373 return(grfaddr(&grf_softc[GRFUNIT(dev)], off));
374 }
375
376
377 grfon(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
397 grfoff(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
416 grfsinfo(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
430 grfaddr(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
453 grfmmap(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 = 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
493 grfunmmap(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
515 int
516 grfbanked_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
534 int
535 grfbanked_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
546 int
547 grfbanked_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