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