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