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