grf_ul.c revision 1.7 1 /* $NetBSD: grf_ul.c,v 1.7 1995/10/09 02:14:46 chopps Exp $ */
2 #define UL_DEBUG
3
4 /*
5 * Copyright (c) 1995 Ignatios Souvatzis
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Lutz Vieweg.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 #include "grful.h"
34 #if NGRFUL > 0
35
36 /* Graphics routines for the University of Lowell A2410 board,
37 using the TMS34010 processor. */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/errno.h>
42 #include <sys/ioctl.h>
43 #include <sys/device.h>
44 #include <sys/malloc.h>
45 #include <sys/syslog.h>
46
47 #include <machine/cpu.h>
48
49 #include <amiga/amiga/device.h>
50 #include <amiga/amiga/isr.h>
51 #include <amiga/dev/zbusvar.h>
52 #include <amiga/dev/grfioctl.h>
53 #include <amiga/dev/grfvar.h>
54 #include <amiga/dev/grf_ulreg.h>
55
56 #include <grf_ultmscode.h>
57
58 int ul_ioctl __P((struct grf_softc *, u_long, void *, dev_t));
59 int ul_getcmap __P((struct grf_softc *, struct grf_colormap *, dev_t));
60 int ul_putcmap __P((struct grf_softc *, struct grf_colormap *, dev_t));
61 int ul_bitblt __P((struct grf_softc *, struct grf_bitblt *, dev_t));
62
63 /*
64 * marked true early so that ulowell_cnprobe() can tell if we are alive.
65 */
66 int ulowell_inited;
67
68 /* standard-palette definition */
69 u_int8_t ul_std_palette[] = {
70 0,128, 0,128, 0,128, 0,128, 0,255, 0,255, 0,255, 0,255,
71 0, 0,128,128, 0, 0,128,128, 0, 0,255,255, 0, 0,255,255,
72 0, 0, 0, 0, 128,128,128,128, 0, 0, 0, 0, 255,255,255,255};
73
74 u_int8_t ul_ovl_palette[] = {
75 128, 0, 0, 0,
76 128, 0, 0, 0,
77 128, 0, 0, 0};
78
79 struct grfvideo_mode ul_monitor_defs[] = {
80
81 /*
82 * Horizontal values are given in TMS units, that is, for the
83 * A2410 board, units of 16 pixels. The ioctl multiplies (when
84 * exporting) or divides (when importing) them by 2 to conform to
85 * the other grfs.
86 *
87 * XXX This should have been in units of pixels, IMHO. If you change
88 * this, you must also change amiga/stand/grfconfig/grfconfig.c,
89 * grf_{rt,rh,cl}.c and egsgrfconfig (the latter to generate the
90 * horizontal timings in units of pixels instead of 8 pixels.
91 * You will also have to write warnings in BIG BOLD RED BLINKING
92 * LETTERS all over the docs, and still people will fry their monitors.
93 *
94 * btw, the _totals are always sync_start+1, to compute the frequencies
95 * correctly. (see TMS34010 manual)
96 */
97
98 /* 1024x768, 60Hz */
99 {1, "1024x768", 66667000, 1024, 768, 8,
100 82, 18, 86, 12, 87, 794, 26, 797, 2, 798},
101
102 /* 864x648, 70Hz */
103 {2, "864x648", 50000000, 864, 648, 8,
104 61, 7, 65, 3, 66, 667, 19, 677, 4, 678},
105
106 /* 800x600, 60Hz */
107 {3, "800x600", 36000000, 800, 600, 8,
108 57, 7, 61, 3, 62, 619, 19, 629, 4, 630},
109
110 /* 640x400, 60 Hz, interlaced */
111 {4, "640x400I", 14318000, 640, 400, 8,
112 48, 8, 56, 3, 57, 239, 39, 262, 2, 240},
113
114 /* 1024x768, 65Hz interlaced, s.th. is strange */
115 {5, "1024x768?I", 44980000, 1024, 768, 8,
116 76, 12, 79, 3, 80, 512, 24, 533, 2, 534},
117
118 /* 1024x1024, 60Hz */
119 {6, "1024x1024", 80000000, 1024,1024, 8,
120 77, 13, 78, 5, 78,1051, 27,1054, 2,1055},
121
122 /* 736x480, 60 Hz */
123 {7, "736x480", 28636300, 736, 480, 8,
124 54, 8, 57, 3, 58, 503, 23, 514, 3, 515},
125 };
126
127 int ulowell_mon_max = sizeof (ul_monitor_defs)/sizeof (ul_monitor_defs[0]);
128
129 /* option settable */
130 #ifndef ULOWELL_OSC1
131 #define ULOWELL_OSC1 36000000
132 #endif
133
134 #ifndef ULOWELL_OSC2
135 #define ULOWELL_OSC2 66667000
136 #endif
137
138 #ifndef ULOWELL_DEFAULT_MON
139 #define ULOWELL_DEFAULT_MON 1
140 #endif
141
142 /* patchable */
143 int ulowell_default_mon = ULOWELL_DEFAULT_MON;
144 int ulowell_default_gfx = ULOWELL_DEFAULT_MON;
145
146 /*
147 * yes, this should be per board. We don't pay service to multiple boards,
148 * anyway.
149 */
150
151 u_long ulowell_clock[2] = { ULOWELL_OSC2, ULOWELL_OSC1 };
152
153 static struct grfvideo_mode *current_mon;
154
155 /*
156 * We dont use ints at the moment, but will need this later to avoid
157 * busy_waiting in gsp_write, and we use it for spurious int warnings.
158 */
159
160 static int
161 ulisr(gp)
162 struct grf_softc *gp;
163 {
164 struct gspregs *ba;
165 u_int16_t thebits;
166
167 if (gp == NULL)
168 return 0;
169
170 ba = (struct gspregs *)gp->g_regkva;
171
172 if (ba == NULL)
173 return 0;
174
175 thebits = ba->ctrl;
176 if (thebits & INTOUT) {
177 log(LOG_INFO, "grf4: got interrupt, ctrl=0x%4x\n", thebits);
178 /* clear int */
179 ba->ctrl = thebits & ~INTOUT;
180 return 1;
181 }
182 return 0;
183 }
184
185 /*
186 * used to query the ulowell board to see if its alive.
187 * for the moment, a NOP.
188 */
189 int
190 ulowell_alive(mdp)
191 struct grfvideo_mode *mdp;
192 {
193 return 1;
194 }
195
196 /*
197 * Load the (mostly) ite support code and the default colormaps.
198 */
199 static void
200 ul_load_code(gp)
201 struct grf_softc *gp;
202 {
203 struct grf_ul_softc *gup;
204 struct gspregs *ba;
205 struct grfinfo *gi;
206 struct grf_colormap gcm;
207 int i,j;
208
209 gup = (struct grf_ul_softc *)gp;
210 ba = (struct gspregs *)gp->g_regkva;
211 gi = &gp->g_display;
212
213 gi->gd_regaddr = ztwopa((caddr_t)ba);
214 gi->gd_regsize = sizeof(struct gspregs);
215 gi->gd_fbaddr = NULL;
216 gi->gd_fbsize = 0;
217 gi->gd_fbwidth = 1024;
218 gi->gd_fbheight = 1024;
219 gi->gd_colors = 256;
220
221 ba->ctrl = (ba->ctrl & ~INCR) | (LBL|INCW);
222 ba->hstadrh = 0xC000;
223 ba->hstadrl = 0x0080;
224 ba->data = 0x0; /* disable screen refresh and video output */
225 ba->data = 0xFFFC; /* screen refresh base address */
226 ba->data = 0xFFFF; /* no display int possible */
227 ba->data = 0x000C; /* CAS before RAS refresh each 64 local clks */
228
229 ba->ctrl = (ba->ctrl & ~INCW) | LBL;
230 ba->hstadrh = 0xfe80;
231 ba->hstadrl = 0;
232 ba->data = 4;
233 ba->hstadrl = 0x20;
234 ba->data = 0xFF; /* all color planes visible */
235
236 ba->hstadrl = 0;
237 ba->data = 5;
238 ba->hstadrl = 0x20;
239 ba->data = 0; /* no color planes blinking */
240
241 ba->hstadrl = 0;
242 ba->data = 6;
243 ba->hstadrl = 0x20;
244 ba->data = gup->gus_ovslct = 0x43;
245 /* overlay visible, no overlay blinking, overlay color 0 transparent */
246
247 ba->hstadrl = 0;
248 ba->data = 7;
249 ba->hstadrl = 0x20;
250 ba->data = 0; /* voodoo */
251
252 /* clear overlay planes */
253 ba->ctrl |= INCW;
254 ba->hstadrh = 0xff80;
255 ba->hstadrl = 0x0000;
256 for (i=0xff80000; i< 0xffa0000; ++i) {
257 ba->data = 0;
258 }
259
260 /* download tms code */
261
262 ba->ctrl = LBL | INCW | NMI | NMIM | HLT | CF;
263
264 printf("\ndownloading TMS code");
265 i=0;
266 while ((j = tmscode[i++])) {
267 printf(".");
268 ba->hstadrh = tmscode[i++];
269 ba->hstadrl = tmscode[i++];
270 while (j-- > 0) {
271 ba->data = tmscode[i++];
272 }
273 }
274
275 /* font info was uploaded in ite_ul.c(ite_ulinit). */
276
277 /* unflush cache, unhalt cpu -> nmi starts to run */
278 ba->ctrl &= ~(HLT|CF);
279
280 #if 0
281 /* XXX load image palette with some initial values, slightly hacky */
282
283 ba->hstadrh = 0xfe80;
284 ba->hstadrl = 0x0000;
285 ba->ctrl |= INCW;
286 ba->data = 0;
287 ba->ctrl &= ~INCW;
288
289 for (i=0; i<16; ++i) {
290 ba->data = gup->gus_imcmap[i+ 0] = ul_std_palette[i+ 0];
291 ba->data = gup->gus_imcmap[i+256] = ul_std_palette[i+16];
292 ba->data = gup->gus_imcmap[i+512] = ul_std_palette[i+32];
293 }
294
295 /*
296 * XXX load shadow overlay palette with what the TMS code will load
297 * into the real one some time after the TMS code is started above.
298 * This is a rude hack.
299 */
300 bcopy(ul_ovl_palette, gup->gus_ovcmap, 3*4);
301 #else
302 /* XXX This version will work for the overlay, if our queue codes
303 * initial conditions are set at load time (not start time).
304 * It further assumes that ul_putcmap only uses the
305 * GRFIMDEV/GRFOVDEV bits of the dev parameter.
306 */
307
308 gcm.index = 0;
309 gcm.count = 16;
310 gcm.red = ul_std_palette + 0;
311 gcm.green = ul_std_palette + 16;
312 gcm.blue = ul_std_palette + 32;
313 ul_putcmap(gp, &gcm, GRFIMDEV);
314
315 gcm.index = 0;
316 gcm.count = 4;
317 gcm.red = ul_ovl_palette + 0;
318 gcm.green = ul_ovl_palette + 4;
319 gcm.blue = ul_ovl_palette + 8;
320 ul_putcmap(gp, &gcm, GRFOVDEV);
321 #endif
322
323 }
324
325 static int
326 ul_load_mon(gp, md)
327 struct grf_softc *gp;
328 struct grfvideo_mode *md;
329 {
330 struct grf_ul_softc *gup;
331 struct grfinfo *gi;
332 struct gspregs *ba;
333 u_int16_t buf[8];
334
335 gup = (struct grf_ul_softc *)gp;
336 gi = &gp->g_display;
337 ba = (struct gspregs *)gp->g_regkva;
338
339 gi->gd_dyn.gdi_fbx = 0;
340 gi->gd_dyn.gdi_fby = 0;
341 gi->gd_dyn.gdi_dwidth = md->disp_width;
342 gi->gd_dyn.gdi_dheight = md->disp_height;
343 gi->gd_dyn.gdi_dx = 0;
344 gi->gd_dyn.gdi_dy = 0;
345
346 ba->ctrl = (ba->ctrl & ~INCR) | (LBL|INCW);
347
348 ba->hstadrh = 0xC000;
349 ba->hstadrl = 0x0000;
350 ba->data = md->hsync_stop;
351 ba->data = md->hblank_stop;
352 ba->data = md->hblank_start;
353 ba->data = md->hsync_start;
354 ba->data = md->vsync_stop;
355 ba->data = md->vblank_stop;
356 ba->data = md->vblank_start;
357 ba->data = md->vsync_start;
358
359 ba->ctrl &= ~INCW;
360 ba->hstadrh = 0xFE90;
361 ba->hstadrl = 0x0000;
362
363 if (abs(md->pixel_clock - ulowell_clock[0]) >
364 abs(md->pixel_clock - ulowell_clock[1])) {
365
366 ba->data = (ba->data & 0xFC) | 2 | 1;
367 md->pixel_clock = ulowell_clock[1];
368
369 } else {
370 ba->data = (ba->data & 0xFC) | 2 | 0;
371 md->pixel_clock = ulowell_clock[0];
372 }
373
374 ba->ctrl |= LBL|INCW;
375 ba->hstadrh = 0xC000;
376 ba->hstadrl = 0x0080;
377 ba->data = (md->vblank_start - md->vblank_stop == md->disp_height ?
378 0xf020 : 0xb020);
379
380 /* I guess this should be in the yet unimplemented mode select ioctl */
381 /* Hm.. maybe not. We always put the console on overlay plane no 0. */
382 /* Anyway, this _IS_ called in the mode select ioctl. */
383
384 /* ite support code parameters: */
385 buf[0] = GCMD_MCHG;
386 buf[1] = md->disp_width; /* display width */
387 buf[2] = md->disp_height; /* display height */
388 buf[3] = 0; /* LSW of frame buffer origin */
389 buf[4] = 0xFF80; /* MSW of frame buffer origin */
390 buf[5] = gi->gd_fbwidth * 1; /* frame buffer pitch */
391 buf[6] = 1; /* frame buffer depth */
392 gsp_write(ba, buf, 7);
393
394 return(1);
395 }
396
397 int ul_mode __P((struct grf_softc *, int, void *, int , int));
398
399 void grfulattach __P((struct device *, struct device *, void *));
400 int grfulprint __P((void *, char *));
401 int grfulmatch __P((struct device *, struct cfdata *, void *));
402
403 struct cfdriver grfulcd = {
404 NULL, "grful", (cfmatch_t)grfulmatch, grfulattach,
405 DV_DULL, sizeof(struct grf_ul_softc), NULL, 0 };
406
407 /*
408 * only used in console init
409 */
410 static struct cfdata *cfdata;
411
412 /*
413 * we make sure to only init things once. this is somewhat
414 * tricky regarding the console.
415 */
416 int
417 grfulmatch(pdp, cfp, auxp)
418 struct device *pdp;
419 struct cfdata *cfp;
420 void *auxp;
421 {
422 #ifdef ULOWELLCONSOLE
423 static int ulconunit = -1;
424 #endif
425 struct zbus_args *zap;
426
427 zap = auxp;
428
429 /*
430 * allow only one ulowell console
431 */
432 if (amiga_realconfig == 0)
433 #ifdef ULOWELLCONSOLE
434 if (ulconunit != -1)
435 #endif
436 return(0);
437
438 if (zap->manid != 1030 || zap->prodid != 0)
439 return(0);
440
441 #ifdef ULOWELLCONSOLE
442 if (amiga_realconfig == 0 || ulconunit != cfp->cf_unit) {
443 #endif
444 if ((unsigned)ulowell_default_mon >= ulowell_mon_max)
445 ulowell_default_mon = 1;
446
447 current_mon = ul_monitor_defs + ulowell_default_mon - 1;
448 if (ulowell_alive(current_mon) == 0)
449 return(0);
450 #ifdef ULOWELLCONSOLE
451 if (amiga_realconfig == 0) {
452 ulconunit = cfp->cf_unit;
453 cfdata = cfp;
454 }
455 }
456 #endif
457 return(1);
458 }
459
460 /*
461 * attach to the grfbus (zbus)
462 */
463 void
464 grfulattach(pdp, dp, auxp)
465 struct device *pdp, *dp;
466 void *auxp;
467 {
468 static struct grf_ul_softc congrf;
469 struct zbus_args *zap;
470 struct grf_softc *gp;
471 struct grf_ul_softc *gup;
472
473 zap = auxp;
474
475 if (dp == NULL)
476 gup = &congrf;
477 else
478 gup = (struct grf_ul_softc *)dp;
479
480 gp = &gup->gus_sc;
481
482 if (dp != NULL && congrf.gus_sc.g_regkva != 0) {
483 /*
484 * inited earlier, just copy (not device struct)
485 */
486 bcopy(&congrf.gus_sc.g_display, &gp->g_display,
487 (char *)&gup->gus_isr - (char *)&gp->g_display);
488
489 /* ...and transfer the isr */
490 gup->gus_isr.isr_ipl = 2;
491 gup->gus_isr.isr_intr = ulisr;
492 gup->gus_isr.isr_arg = (void *)gp;
493 /*
494 * To make sure ints are always catched, first add new isr
495 * then remove old:
496 */
497 add_isr(&gup->gus_isr);
498 remove_isr(&congrf.gus_isr);
499 } else {
500 gp->g_regkva = (caddr_t)zap->va;
501 gp->g_fbkva = NULL;
502 gp->g_unit = GRF_ULOWELL_UNIT;
503 gp->g_flags = GF_ALIVE;
504 gp->g_mode = ul_mode;
505 gp->g_conpri = grful_cnprobe();
506 gp->g_data = NULL;
507
508 gup->gus_isr.isr_ipl = 2;
509 gup->gus_isr.isr_intr = ulisr;
510 gup->gus_isr.isr_arg = (void *)gp;
511 add_isr(&gup->gus_isr);
512
513 (void)ul_load_code(gp);
514 (void)ul_load_mon(gp, current_mon);
515 grful_iteinit(gp);
516 }
517 if (dp != NULL)
518 printf("\n");
519 /*
520 * attach grf
521 */
522 amiga_config_found(cfdata, &gp->g_device, gp, grfulprint);
523 }
524
525 int
526 grfulprint(auxp, pnp)
527 void *auxp;
528 char *pnp;
529 {
530 if (pnp)
531 printf("grf%d at %s", ((struct grf_softc *)auxp)->g_unit,
532 pnp);
533 return(UNCONF);
534 }
535
536 static int
537 ul_getvmode (gp, vm)
538 struct grf_softc *gp;
539 struct grfvideo_mode *vm;
540 {
541 struct grfvideo_mode *md;
542
543 if (vm->mode_num && vm->mode_num > ulowell_mon_max)
544 return EINVAL;
545
546 if (! vm->mode_num)
547 vm->mode_num = current_mon - ul_monitor_defs + 1;
548
549 md = ul_monitor_defs + vm->mode_num - 1;
550 strncpy (vm->mode_descr, md->mode_descr,
551 sizeof (vm->mode_descr));
552
553 /* XXX should tell TMS to measure it */
554 vm->pixel_clock = md->pixel_clock;
555 vm->disp_width = md->disp_width;
556 vm->disp_height = md->disp_height;
557 vm->depth = md->depth;
558
559 /* XXX should use 16 instead of 2, but others use 1 instead of 8 */
560
561 /*
562 * XXX another idea: maybe we should transform the timings to
563 * have blank stop as point of reference (like other grfs) instead
564 * of sync start?
565 */
566
567 vm->hblank_start = (md->hblank_start - md->hblank_stop) * 2;
568 vm->hblank_stop = (md->htotal - 1) * 2;
569 vm->hsync_start = (md->hsync_start - md->hblank_stop) * 2;
570 vm->hsync_stop = (md->hsync_stop + md->htotal - md->hblank_stop) * 2;
571 vm->htotal = md->htotal * 2;
572
573 vm->vblank_start = md->vblank_start - md->vblank_stop;
574 vm->vblank_stop = md->vtotal - 1;
575 vm->vsync_start = md->vsync_start - md->vblank_stop;
576 vm->vsync_stop = md->vsync_stop + md->vtotal - md->vblank_stop;
577 vm->vtotal = md->vtotal;
578
579 return 0;
580 }
581
582
583 static int
584 ul_setvmode (gp, mode)
585 struct grf_softc *gp;
586 unsigned mode;
587 {
588 struct grf_ul_softc *gup;
589 struct gspregs *ba;
590 int error;
591
592 if (!mode || mode > ulowell_mon_max)
593 return EINVAL;
594
595 ba = (struct gspregs *)gp->g_regkva;
596 gup = (struct grf_ul_softc *)gp;
597 current_mon = ul_monitor_defs + mode - 1;
598
599 error = ul_load_mon (gp, current_mon) ? 0 : EINVAL;
600
601 return error;
602 }
603
604 /*
605 * Set the frame buffer or overlay planes on or off.
606 * Always succeeds.
607 */
608
609 static __inline void
610 ul_setfb(gp, cmd)
611 struct grf_softc *gp;
612 int cmd;
613 {
614 struct grf_ul_softc *gup;
615 struct gspregs *ba;
616
617 gup = (struct grf_ul_softc *)gp;
618
619 ba = (struct gspregs *)gp->g_regkva;
620 ba->ctrl = LBL;
621 ba->hstadrh = 0xfe80;
622 ba->hstadrl = 0x0000;
623 ba->data = 6;
624 ba->hstadrl = 0x0020;
625
626 switch (cmd) {
627 case GM_GRFON:
628 gup->gus_ovslct |= 0x40;
629 break;
630 case GM_GRFOFF:
631 gup->gus_ovslct &= ~0x40;
632 break;
633 case GM_GRFOVON:
634 gup->gus_ovslct |= 3;
635 break;
636 case GM_GRFOVOFF:
637 gup->gus_ovslct &= ~3;
638 break;
639 }
640 ba->data = gup->gus_ovslct;
641 }
642
643 /*
644 * Change the mode of the display.
645 * Return a UNIX error number or 0 for success.
646 */
647 int
648 ul_mode(gp, cmd, arg, a2, a3)
649 struct grf_softc *gp;
650 int cmd;
651 void *arg;
652 int a2, a3;
653 {
654 int i;
655 struct grfdyninfo *gd;
656
657 switch (cmd) {
658 case GM_GRFON:
659 case GM_GRFOFF:
660 case GM_GRFOVON:
661 case GM_GRFOVOFF:
662 ul_setfb (gp, cmd);
663 return 0;
664
665 case GM_GRFCONFIG:
666 gd = (struct grfdyninfo *)arg;
667 for (i=0; i<ulowell_mon_max; ++i) {
668 if (ul_monitor_defs[i].disp_width == gd->gdi_dwidth &&
669 ul_monitor_defs[i].disp_height == gd->gdi_dheight)
670 return ul_setvmode(gp, i+1);
671 }
672 return EINVAL;
673
674 case GM_GRFGETVMODE:
675 return ul_getvmode (gp, (struct grfvideo_mode *) arg);
676
677 case GM_GRFSETVMODE:
678 return ul_setvmode (gp, *(unsigned *) arg);
679
680 case GM_GRFGETNUMVM:
681 *(int *)arg = ulowell_mon_max;
682 return 0;
683
684 case GM_GRFIOCTL:
685 return ul_ioctl (gp, (u_long)arg, (void *)a2, (dev_t)a3);
686
687 default:
688 break;
689 }
690
691 return EINVAL;
692 }
693
694 int
695 ul_ioctl (gp, cmd, data, dev)
696 register struct grf_softc *gp;
697 u_long cmd;
698 void *data;
699 dev_t dev;
700 {
701 switch (cmd) {
702 #if 0
703 /*
704 * XXX we have no hardware sprites, but might implement them
705 * later in TMS code.
706 */
707
708 case GRFIOCGSPRITEPOS:
709 return ul_getspritepos (gp, (struct grf_position *) data);
710
711 case GRFIOCSSPRITEPOS:
712 return ul_setspritepos (gp, (struct grf_position *) data);
713
714 case GRFIOCSSPRITEINF:
715 return ul_setspriteinfo (gp, (struct grf_spriteinfo *) data);
716
717 case GRFIOCGSPRITEINF:
718 return ul_getspriteinfo (gp, (struct grf_spriteinfo *) data);
719
720 case GRFIOCGSPRITEMAX:
721 return ul_getspritemax (gp, (struct grf_position *) data);
722
723 #endif
724
725 case GRFIOCGETCMAP:
726 return ul_getcmap (gp, (struct grf_colormap *) data, dev);
727
728 case GRFIOCPUTCMAP:
729 return ul_putcmap (gp, (struct grf_colormap *) data, dev);
730
731 case GRFIOCBITBLT:
732 return ul_bitblt (gp, (struct grf_bitblt *) data, dev);
733 }
734
735 return EINVAL;
736 }
737
738 int
739 ul_getcmap (gp, cmap, dev)
740 struct grf_softc *gp;
741 struct grf_colormap *cmap;
742 dev_t dev;
743 {
744 struct grf_ul_softc *gup;
745 u_int8_t *mymap;
746 int mxidx, error;
747
748 gup = (struct grf_ul_softc *)gp;
749
750 if (minor(dev) & GRFIMDEV) {
751 mxidx = 256;
752 mymap = gup->gus_imcmap;
753 } else {
754 mxidx = 4;
755 mymap = gup->gus_ovcmap;
756 }
757
758 if (cmap->count == 0 || cmap->index >= mxidx)
759 return 0;
760
761 if (cmap->index + cmap->count > mxidx)
762 cmap->count = mxidx - cmap->index;
763
764 /* just copyout from the shadow color map */
765
766 if ((error = copyout(mymap + cmap->index, cmap->red, cmap->count))
767
768 || (error = copyout(mymap + mxidx + cmap->index, cmap->green,
769 cmap->count))
770
771 || (error = copyout(mymap + mxidx * 2 + cmap->index, cmap->blue,
772 cmap->count)))
773
774 return(error);
775
776 return(0);
777 }
778
779 int
780 ul_putcmap (gp, cmap, dev)
781 struct grf_softc *gp;
782 struct grf_colormap *cmap;
783 dev_t dev;
784 {
785 struct grf_ul_softc *gup;
786 struct gspregs *ba;
787 u_int16_t cmd[8];
788 int x, mxidx, error;
789 u_int8_t *mymap;
790
791 gup = (struct grf_ul_softc *)gp;
792
793 if (minor(dev) & GRFIMDEV) {
794 mxidx = 256;
795 mymap = gup->gus_imcmap;
796 } else {
797 mxidx = 4;
798 mymap = gup->gus_ovcmap;
799 }
800
801 if (cmap->count == 0 || cmap->index >= mxidx)
802 return 0;
803
804 if (cmap->index + cmap->count > mxidx)
805 cmap->count = mxidx - cmap->index;
806
807 /* first copyin to our shadow color map */
808
809 if ((error = copyin(cmap->red, mymap + cmap->index, cmap->count))
810
811 || (error = copyin(cmap->green, mymap + cmap->index + mxidx,
812 cmap->count))
813
814 || (error = copyin(cmap->blue, mymap + cmap->index + mxidx*2,
815 cmap->count)))
816
817 return error;
818
819
820 /* then write from there to the hardware */
821 ba = (struct gspregs *)gp->g_regkva;
822 if (mxidx > 4) {
823 /* image color map: we can write, with a hack, directly */
824 ba->ctrl = LBL;
825 ba->hstadrh = 0xfe80;
826 ba->hstadrl = 0x0000;
827 ba->ctrl |= INCW;
828 ba->data = cmap->index;
829 ba->ctrl &= ~INCW;
830
831 for (x=cmap->index; x < cmap->index + cmap->count; ++x) {
832 ba->data = (u_int16_t) mymap[x];
833 ba->data = (u_int16_t) mymap[x + mxidx];
834 ba->data = (u_int16_t) mymap[x + mxidx * 2];
835 }
836 } else {
837
838 /* overlay planes color map: have to call tms to do it */
839 cmd[0] = GCMD_CMAP;
840 cmd[1] = 1;
841 for (x=cmap->index; x < cmap->index + cmap->count; ++x) {
842 cmd[2] = x;
843 cmd[3] = mymap[x];
844 cmd[4] = mymap[x + mxidx];
845 cmd[5] = mymap[x + mxidx * 2];
846 gsp_write(ba, cmd, 6);
847 }
848 }
849 return 0;
850 }
851
852 /*
853 * !!! THIS AREA UNDER CONSTRUCTION !!!
854 */
855 int ul_BltOpMap[16] = {
856 3, 1, 2, 0, 11, 9, 10, 8,
857 7, 5, 6, 4, 15, 13, 14, 12
858 };
859
860 int
861 ul_bitblt (gp, bb, dev)
862 struct grf_softc *gp;
863 struct grf_bitblt *bb;
864 dev_t dev;
865 {
866 /* XXX not yet implemented, but pretty trivial */
867 return EINVAL;
868 }
869
870 void
871 gsp_write(gsp, ptr, size)
872 struct gspregs *gsp;
873 u_short *ptr;
874 size_t size;
875 {
876 u_short put, new_put, next, oc;
877 u_long put_hi, oa;
878 size_t n;
879
880 if (size == 0 || size > 8)
881 return;
882
883 n = size;
884
885 oc = gsp->ctrl;
886 oa = GSPGETHADRS(gsp);
887
888 gsp->ctrl = (oc & ~INCR) | LBL | INCW;
889 GSPSETHADRS(gsp, GSP_MODE_ADRS);
890 gsp->data &= ~GMODE_FLUSH;
891
892 GSPSETHADRS(gsp, PUT_HI_PTR_ADRS);
893 put_hi = gsp->data << 16;
894
895 GSPSETHADRS(gsp, PUT_PTR_ADRS);
896 put = gsp->data;
897 new_put = put + (8<<4);
898
899 GSPSETHADRS(gsp, GET_PTR_ADRS);
900 next = gsp->data;
901
902 while (next == new_put) {
903 /*
904 * we should use an intr. here. unfortunately, we already
905 * are called from an interupt and can't use tsleep.
906 * so we do busy waiting, at least for the moment.
907 */
908
909 GSPSETHADRS(gsp,GET_PTR_ADRS);
910 next = gsp->data;
911 }
912
913 GSPSETHADRS(gsp,put|put_hi);
914 gsp->data = *ptr++ | 8<<4;
915 while ( --n > 0) {
916 gsp->data = *ptr++;
917 }
918
919 GSPSETHADRS(gsp,PUT_PTR_ADRS);
920 gsp->data = new_put;
921 GSPSETHADRS(gsp,oa);
922 gsp->ctrl = oc;
923
924 return;
925 }
926
927 #endif /* NGRF */
928