grf_cv.c revision 1.52.6.1 1 /* $NetBSD: grf_cv.c,v 1.52.6.1 2012/02/18 07:31:16 mrg Exp $ */
2
3 /*
4 * Copyright (c) 1995 Michael Teske
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Ezra Story, by Kari
18 * Mettinen, Michael Teske and by Bernd Ernesti.
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 "opt_amigacons.h"
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: grf_cv.c,v 1.52.6.1 2012/02/18 07:31:16 mrg Exp $");
37
38 #include "grfcv.h"
39 #include "ite.h"
40 #include "wsdisplay.h"
41 #if NGRFCV > 0
42
43 /*
44 * Graphics routines for the CyberVision 64 board, using the S3 Trio64.
45 *
46 * Modified for CV64 from
47 * Kari Mettinen's Cirrus driver by Michael Teske 10/95
48 *
49 * Thanks to Tekelec Airtronic for providing me with a S3 Trio64 documentation.
50 * Thanks to Bernd 'the fabulous bug-finder' Ernesti for bringing my messy
51 * source to NetBSD style :)
52 * Thanks to Harald Koenig for providing information about undocumented
53 * Trio64 Bugs.
54 */
55
56 #include <sys/param.h>
57 #include <sys/errno.h>
58 #include <sys/ioctl.h>
59 #include <sys/device.h>
60 #include <sys/malloc.h>
61 #include <sys/systm.h>
62 #include <sys/syslog.h>
63
64 #include <machine/cpu.h>
65
66 #include <dev/cons.h>
67 #if NWSDISPLAY > 0
68 #include <dev/wscons/wsconsio.h>
69 #include <dev/wscons/wsdisplayvar.h>
70 #include <dev/rasops/rasops.h>
71 #include <dev/wscons/wsdisplay_vconsvar.h>
72 #endif
73
74 #include <amiga/dev/itevar.h>
75 #include <amiga/amiga/device.h>
76 #include <amiga/amiga/isr.h>
77 #include <amiga/dev/grfioctl.h>
78 #include <amiga/dev/grfws.h>
79 #include <amiga/dev/grfvar.h>
80 #include <amiga/dev/grf_cvreg.h>
81 #include <amiga/dev/zbusvar.h>
82
83 int grfcvmatch(struct device *, struct cfdata *, void *);
84 void grfcvattach(struct device *, struct device *, void *);
85 int grfcvprint(void *, const char *);
86
87 int cvintr(void *);
88 static int cv_has_4mb(volatile void *);
89 static unsigned short cv_compute_clock(unsigned long);
90 void cv_boardinit(struct grf_softc *);
91 int cv_getvmode(struct grf_softc *, struct grfvideo_mode *);
92 int cv_setvmode(struct grf_softc *, unsigned int);
93 int cv_blank(struct grf_softc *, int *);
94 int cv_mode(register struct grf_softc *, u_long, void *, u_long, int);
95 int cv_ioctl(register struct grf_softc *gp, u_long cmd, void *data);
96 int cv_setmonitor(struct grf_softc *, struct grfvideo_mode *);
97 int cv_getcmap(struct grf_softc *, struct grf_colormap *);
98 int cv_putcmap(struct grf_softc *, struct grf_colormap *);
99 int cv_toggle(struct grf_softc *);
100 int cv_mondefok(struct grfvideo_mode *);
101 int cv_load_mon(struct grf_softc *, struct grfcvtext_mode *);
102 void cv_inittextmode(struct grf_softc *);
103 static inline void cv_write_port(unsigned short, volatile void *);
104 static inline void cvscreen(int, volatile void *);
105 static inline void gfx_on_off(int, volatile void *);
106
107 #ifndef CV_NO_HARDWARE_CURSOR
108 int cv_getspritepos(struct grf_softc *, struct grf_position *);
109 int cv_setspritepos(struct grf_softc *, struct grf_position *);
110 int cv_getspriteinfo(struct grf_softc *,struct grf_spriteinfo *);
111 void cv_setup_hwc(struct grf_softc *);
112 int cv_setspriteinfo(struct grf_softc *,struct grf_spriteinfo *);
113 int cv_getspritemax(struct grf_softc *,struct grf_position *);
114 #endif /* !CV_NO_HARDWARE_CURSOR */
115
116 /*
117 * Extension to grf_softc for interrupt support
118 */
119
120 struct grf_cv_softc {
121 struct grf_softc gcs_sc;
122 struct isr gcs_isr;
123 };
124
125 /* Graphics display definitions.
126 * These are filled by 'grfconfig' using GRFIOCSETMON.
127 */
128 #define monitor_def_max 24
129 static struct grfvideo_mode monitor_def[24] = {
130 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
131 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
132 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}
133 };
134 static struct grfvideo_mode *monitor_current = &monitor_def[0];
135 #define MAXPIXELCLOCK 135000000 /* safety */
136
137 unsigned char cv_pass_toggle; /* passthru status tracker */
138
139 /* Console display definition.
140 * Default hardcoded text mode. This grf_cv is set up to
141 * use one text mode only, and this is it. You may use
142 * grfconfig to change the mode after boot.
143 */
144
145 /* Console font */
146 #ifdef KFONT_8X11
147 #define S3FONT kernel_font_8x11
148 #define S3FONTY 11
149 #else
150 #define S3FONT kernel_font_8x8
151 #define S3FONTY 8
152 #endif
153 extern unsigned char S3FONT[];
154
155 /*
156 * Define default console mode
157 * (Internally, we still have to use hvalues/8!)
158 */
159 struct grfcvtext_mode cvconsole_mode = {
160 {255, "", 25000000, 640, 480, 4, 640/8, 680/8, 768/8, 800/8,
161 481, 491, 493, 525, 0},
162 8, S3FONTY, 80, 480 / S3FONTY, S3FONT, 32, 255
163 };
164
165 /* Console colors */
166 unsigned char cvconscolors[16][3] = { /* background, foreground, hilite */
167 /* R G B */
168 {0x30, 0x30, 0x30},
169 {0x00, 0x00, 0x00},
170 {0x80, 0x00, 0x00},
171 {0x00, 0x80, 0x00},
172 {0x00, 0x00, 0x80},
173 {0x80, 0x80, 0x00},
174 {0x00, 0x80, 0x80},
175 {0x80, 0x00, 0x80},
176 {0xff, 0xff, 0xff},
177 {0x40, 0x40, 0x40},
178 {0xff, 0x00, 0x00},
179 {0x00, 0xff, 0x00},
180 {0x00, 0x00, 0xff},
181 {0xff, 0xff, 0x00},
182 {0x00, 0xff, 0xff},
183 {0x00, 0x00, 0xff}
184 };
185
186 static unsigned char clocks[]={
187 0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69,
188 0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c,
189 0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a,
190 0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69,
191 0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65,
192 0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63,
193 0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d,
194 0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49,
195 0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42,
196 0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43,
197 0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49,
198 0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a,
199 0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49,
200 0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41,
201 0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43,
202 0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45,
203 0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45,
204 0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45,
205 0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44,
206 0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46,
207 0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f,
208 0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22,
209 0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46,
210 0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b,
211 0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44,
212 0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26,
213 0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b,
214 0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25,
215 0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25,
216 0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21,
217 0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29,
218 0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29,
219 0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29,
220 0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28,
221 0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26,
222 0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21,
223 0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28,
224 0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27,
225 0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22,
226 0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27,
227 0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27,
228 0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21,
229 0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26,
230 0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27,
231 0x13, 0x1, 0x13, 0x1, 0x7d, 0x27, 0x4c, 0x9,
232 0x37, 0x22, 0x5b, 0xb, 0x71, 0x26, 0x5c, 0xb,
233 0x6b, 0xd, 0x47, 0x23, 0x14, 0x1, 0x4f, 0x9,
234 0x23, 0x3, 0x75, 0x26, 0x7d, 0xf, 0x1c, 0x2,
235 0x51, 0x9, 0x59, 0x24, 0x61, 0xb, 0x69, 0x25,
236 0x79, 0x26, 0x34, 0x5, 0x1d, 0x2, 0x6b, 0x25,
237 0x54, 0x9, 0x35, 0x5, 0x45, 0x7, 0x6d, 0x25,
238 0x7d, 0x26, 0x16, 0x1, 0x7f, 0x26, 0x77, 0xd,
239 0x4f, 0x23, 0x78, 0xd, 0x2f, 0x21, 0x27, 0x3,
240 0x1f, 0x2, 0x59, 0x9, 0x6a, 0xb, 0x73, 0x25,
241 0x6b, 0xb, 0x63, 0x24, 0x5b, 0x9, 0x20, 0x2,
242 0x7e, 0xd, 0x4b, 0x7, 0x65, 0x24, 0x43, 0x22,
243 0x18, 0x1, 0x6f, 0xb, 0x5e, 0x9, 0x70, 0xb,
244 0x2a, 0x3, 0x33, 0x4, 0x45, 0x6, 0x60, 0x9,
245 0x7b, 0xc, 0x19, 0x1, 0x19, 0x1, 0x7d, 0xc,
246 0x74, 0xb, 0x50, 0x7, 0x75, 0xb, 0x63, 0x9,
247 0x51, 0x7, 0x23, 0x2, 0x3f, 0x5, 0x1a, 0x1,
248 0x65, 0x9, 0x2d, 0x3, 0x40, 0x5, 0x0, 0x0,
249 };
250
251
252 /* Board Address of CV64 */
253 static volatile void *cv_boardaddr;
254 static int cv_fbsize;
255
256 /*
257 * Memory clock (binpatchable).
258 * Let's be defensive: 50 MHz runs on all boards I know of.
259 * 55 MHz runs on most boards. But you should know what you're doing
260 * if you set this flag. Again: This flag may destroy your CV Board.
261 * Use it at your own risk!!!
262 * Anyway, this doesn't imply that I'm responsible if your board breaks
263 * without setting this flag :-).
264 */
265 #ifdef CV_AGGRESSIVE_TIMING
266 long cv_memclk = 55000000;
267 #else
268 long cv_memclk = 50000000;
269 #endif
270
271 #if NWSDISPLAY > 0
272 /* wsdisplay acessops, emulops */
273 static void cv_wscursor(void *, int, int, int);
274 static void cv_wsputchar(void *, int, int, u_int, long);
275 static void cv_wscopycols(void *, int, int, int, int);
276 static void cv_wserasecols(void *, int, int, int, long);
277 static void cv_wscopyrows(void *, int, int, int);
278 static void cv_wseraserows(void *, int, int, long);
279 static int cv_wsallocattr(void *, int, int, int, long *);
280 static int cv_wsmapchar(void *, int, unsigned int *);
281
282 static struct wsdisplay_accessops cv_accessops = {
283 .ioctl = grf_wsioctl,
284 .mmap = grf_wsmmap
285 };
286
287 static struct wsdisplay_emulops cv_textops = {
288 .cursor = cv_wscursor,
289 .mapchar = cv_wsmapchar,
290 .putchar = cv_wsputchar,
291 .copycols = cv_wscopycols,
292 .erasecols = cv_wserasecols,
293 .copyrows = cv_wscopyrows,
294 .eraserows = cv_wseraserows,
295 .allocattr = cv_wsallocattr
296 };
297
298 static struct ws_ao_ioctl cv_wsioctl = {
299 grf_wsaoginfo,
300 grf_wsaogetcmap,
301 grf_wsaoputcmap,
302 grf_wsaogvideo,
303 grf_wsaosvideo,
304 grf_wsaogmode,
305 grf_wsaosmode,
306 grf_wsaogtype
307 };
308
309 static struct wsscreen_descr cv_screen = {
310 .name = "default",
311 .textops = &cv_textops,
312 .fontwidth = 8,
313 .fontheight = S3FONTY,
314 .capabilities = WSSCREEN_HILIT | WSSCREEN_BLINK |
315 WSSCREEN_REVERSE | WSSCREEN_UNDERLINE
316 };
317 #endif /* NWSDISPLAY > 0 */
318
319 /* standard driver stuff */
320 CFATTACH_DECL(grfcv, sizeof(struct grf_cv_softc),
321 grfcvmatch, grfcvattach, NULL, NULL);
322
323 static struct cfdata *cfdata;
324
325 #define CV_INT_NUM 6 /* CV interrupt Level: #2 or #6 */
326 #define CV_ULCURSOR 1 /* Underlined Cursor in textmode */
327
328 #ifndef CV_NO_HARDWARE_CURSOR
329
330 #define HWC_OFF (cv_fbsize - 1024*2)
331 #define HWC_SIZE 1024
332
333 static unsigned short cv_cursor_storage[HWC_SIZE/2];
334 static short curs_update_flag = 0;
335
336 #endif /* !CV_NO_HARDWARE_CURSOR */
337
338 /*
339 * Interrupt handler
340 * This is used for updating the cursor shape (because it _must not_
341 * be changed while cursor is displayed)
342 * and maybe later to avoid busy waiting
343 * for Vertical Blank and/or gfx engine busy
344 */
345
346 int
347 cvintr(void *arg)
348 {
349 #ifndef CV_NO_HARDWARE_CURSOR
350 volatile unsigned long *csrc, *cdest;
351 int i;
352 #endif
353 struct grf_softc *gp = arg;
354 volatile void *ba = gp->g_regkva;
355 unsigned char test;
356 unsigned char cridx; /* Save the cr Register index */
357
358 if (gp == NULL)
359 return 0;
360
361 test = vgar(ba, GREG_INPUT_STATUS0_R);
362
363 if (test & 0x80) { /* VR int pending */
364 /* Save old CR index */
365 cridx = vgar (ba, CRT_ADDRESS);
366
367 #if !defined(__m68k__)
368 test = RCrt(ba, CRT_ID_END_VER_RETR);
369 /* Clear int (bit 4) */
370 test &= ~0x10;
371 WCrt(ba, CRT_ID_END_VER_RETR, test);
372 #else
373 vgaw(ba, CRT_ADDRESS, CRT_ID_END_VER_RETR);
374 __asm volatile("bclr #4,%0@(0x3d5);nop" : : "a" (ba));
375 #endif
376
377 #ifndef CV_NO_HARDWARE_CURSOR
378 /* update the hardware cursor, if necessary */
379 if (curs_update_flag) {
380 csrc = (unsigned long *)cv_cursor_storage;
381 cdest = (volatile unsigned long *)
382 ((volatile char*)gp->g_fbkva + HWC_OFF);
383 for (i = 0; i < HWC_SIZE / sizeof(long); i++)
384 *cdest++ = *csrc++;
385 curs_update_flag = 0;
386 }
387 /* Reenable int */
388 #if !defined(__m68k__)
389 test |= 0x10;
390 WCrt(ba, CRT_ID_END_VER_RETR, test);
391 #else
392 /* I don't trust the optimizer here... */
393 __asm volatile("bset #4,%0@(0x3d5);nop" : : "a" (ba));
394 #endif
395 cv_setspritepos (gp, NULL);
396
397 /* Restore the old CR index */
398 vgaw(ba, CRT_ADDRESS, cridx);
399 amiga_cpu_sync();
400 #endif /* !CV_NO_HARDWARE_CURSOR */
401 return (1);
402 }
403 return (0);
404 }
405
406 /*
407 * Get frambuffer memory size.
408 * phase5 didn't provide the bit in CR36,
409 * so we have to do it this way.
410 * Return 0 for 2MB, 1 for 4MB
411 */
412 static int
413 cv_has_4mb(volatile void *fb)
414 {
415 volatile unsigned long *testfbw, *testfbr;
416
417 /* write patterns in memory and test if they can be read */
418 testfbw = (volatile unsigned long *)fb;
419 testfbr = (volatile unsigned long *)((volatile char*)fb + 0x02000000);
420 *testfbw = 0x87654321;
421 amiga_cpu_sync();
422 if (*testfbr != 0x87654321)
423 return (0);
424
425 /* upper memory region */
426 testfbw = (volatile unsigned long *)((volatile char*)fb + 0x00200000);
427 testfbr = (volatile unsigned long *)((volatile char*)fb + 0x02200000);
428 *testfbw = 0x87654321;
429 amiga_cpu_sync();
430 if (*testfbr != 0x87654321)
431 return (0);
432 *testfbw = 0xAAAAAAAA;
433 amiga_cpu_sync();
434 if (*testfbr != 0xAAAAAAAA)
435 return (0);
436 *testfbw = 0x55555555;
437 amiga_cpu_sync();
438 if (*testfbr != 0x55555555)
439 return (0);
440 return (1);
441 }
442
443 int
444 grfcvmatch(struct device *pdp, struct cfdata *cfp, void *auxp)
445 {
446 #ifdef CV64CONSOLE
447 static int cvcons_unit = -1;
448 #endif
449 struct zbus_args *zap;
450
451 zap = auxp;
452
453 if (amiga_realconfig == 0)
454 #ifdef CV64CONSOLE
455 if (cvcons_unit != -1)
456 #endif
457 return (0);
458
459 /* Lets be Paranoid: Test man and prod id */
460 if (zap->manid != 8512 || zap->prodid != 34)
461 return (0);
462
463 cv_boardaddr = zap->va;
464
465 #ifdef CV64CONSOLE
466 if (amiga_realconfig == 0) {
467 cvcons_unit = cfp->cf_unit;
468 cfdata = cfp;
469 }
470 #endif
471
472 return (1);
473 }
474
475 void
476 grfcvattach(struct device *pdp, struct device *dp, void *auxp)
477 {
478 static struct grf_cv_softc congrf;
479 struct zbus_args *zap;
480 struct grf_softc *gp;
481 struct grf_cv_softc *gcp;
482 static char attachflag = 0;
483
484 zap = auxp;
485
486 /*
487 * This function is called twice, once on console init (dp == NULL)
488 * and once on "normal" grf5 init.
489 */
490
491 if (dp == NULL) /* console init */
492 gcp = &congrf;
493 else
494 gcp = (struct grf_cv_softc *)dp;
495
496 gp = &gcp->gcs_sc;
497
498 if (dp != NULL && congrf.gcs_sc.g_regkva != 0) {
499 /*
500 * inited earlier, just copy (not device struct)
501 */
502
503 printf("\n");
504 memcpy(&gp->g_display, &congrf.gcs_sc.g_display,
505 (char *) &gcp->gcs_isr - (char *) &gp->g_display);
506
507 /* ... and transfer the isr */
508 gcp->gcs_isr.isr_ipl = CV_INT_NUM;
509 gcp->gcs_isr.isr_intr = cvintr;
510 gcp->gcs_isr.isr_arg = (void *)gp;
511
512 /* First add new isr */
513 add_isr(&gcp->gcs_isr);
514 remove_isr(&congrf.gcs_isr);
515 } else {
516 gp->g_regkva = (volatile char *)cv_boardaddr + 0x02000000;
517 gp->g_fbkva = (volatile char *)cv_boardaddr + 0x01400000;
518
519 gp->g_unit = GRF_CV64_UNIT;
520 gp->g_mode = cv_mode;
521 #if NITE > 0
522 gp->g_conpri = grfcv_cnprobe();
523 #endif
524 gp->g_flags = GF_ALIVE;
525
526 /* add Interrupt Handler */
527 gcp->gcs_isr.isr_ipl = CV_INT_NUM;
528 gcp->gcs_isr.isr_intr = cvintr;
529 gcp->gcs_isr.isr_arg = (void *)gp;
530 add_isr(&gcp->gcs_isr);
531
532 /* wakeup the board */
533 cv_boardinit(gp);
534
535 #ifdef CV64CONSOLE
536 #if NWSDISPLAY > 0
537 gp->g_accessops = &cv_accessops;
538 gp->g_emulops = &cv_textops;
539 gp->g_defaultscreen = cv_screen;
540 gp->g_screens[0] = &gp->g_defaultscreen;
541 gp->g_wsioctl = &cv_wsioctl;
542 #else
543 grfcv_iteinit(gp);
544 #endif
545 (void)cv_load_mon(gp, &cvconsole_mode);
546 #endif
547 }
548
549 /*
550 * attach grf
551 */
552 if (amiga_config_found(cfdata, &gp->g_device, gp, grfcvprint)) {
553 if (dp != NULL)
554 printf("grfcv: CyberVision64 with %dMB being used\n",
555 cv_fbsize/0x100000);
556 attachflag = 1;
557 } else {
558 if (!attachflag)
559 /*printf("grfcv unattached!!\n")*/;
560 }
561 }
562
563 int
564 grfcvprint(void *auxp, const char *pnp)
565 {
566 if (pnp)
567 aprint_normal("ite at %s: ", pnp);
568 return (UNCONF);
569 }
570
571
572 /*
573 * Computes M, N, and R values from
574 * given input frequency. It uses a table of
575 * precomputed values, to keep CPU time low.
576 *
577 * The return value consist of:
578 * lower byte: Bits 4-0: N Divider Value
579 * Bits 5-6: R Value for e.g. SR10 or SR12
580 * higher byte: Bits 0-6: M divider value for e.g. SR11 or SR13
581 */
582
583 static unsigned short
584 cv_compute_clock(unsigned long freq)
585 {
586 static unsigned char *mnr, *save; /* M, N + R vals */
587 unsigned long work_freq, r;
588 unsigned short erg;
589 long diff, d2;
590
591 if (freq < 12500000 || freq > MAXPIXELCLOCK) {
592 printf("grfcv: Illegal clock frequency: %ldMHz\n", freq/1000000);
593 printf("grfcv: Using default frequency: 25MHz\n");
594 printf("grfcv: See the manpage of grfconfig for more informations.\n");
595 freq = 25000000;
596 }
597
598 mnr = clocks; /* there the vals are stored */
599 d2 = 0x7fffffff;
600
601 while (*mnr) { /* mnr vals are 0-terminated */
602 work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
603
604 r = (mnr[1] >> 5) & 0x03;
605 if (r != 0)
606 work_freq=work_freq >> r; /* r is the freq divider */
607
608 work_freq *= 0x3E8; /* 2nd part of OSC */
609
610 diff = abs(freq - work_freq);
611
612 if (d2 >= diff) {
613 d2 = diff;
614 /* In save are the vals for minimal diff */
615 save = mnr;
616 }
617 mnr += 2;
618 }
619 erg = *((unsigned short *)save);
620
621 return (erg);
622 }
623
624
625 void
626 cv_boardinit(struct grf_softc *gp)
627 {
628 volatile void *ba;
629 unsigned char test;
630 unsigned int clockpar;
631 int i;
632 struct grfinfo *gi;
633
634 ba = gp->g_regkva;
635 /* Reset board */
636 for (i = 0; i < 6; i++)
637 /* Clear all bits */
638 cv_write_port (0xff, (volatile char*)ba - 0x02000000);
639
640 /* Return to operational Mode */
641 cv_write_port(0x8004, (volatile char*)ba - 0x02000000);
642
643 /* Wakeup Chip */
644 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x10);
645 vgaw(ba, SREG_OPTION_SELECT, 0x01);
646 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x08);
647
648 vgaw(ba, GREG_MISC_OUTPUT_W, 0x03);
649
650 WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock S3 VGA regs */
651 WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5); /* unlock syscontrol */
652
653 /*
654 * The default board interrupt is #6.
655 * Set the roxxler register to use interrupt #2, not #6.
656 */
657 #if CV_INT_NUM == 2
658 cv_write_port(0x8080, (volatile char*)ba - 0x02000000);
659 #endif
660
661 /* Enable board interrupts */
662 cv_write_port(0x8008, (volatile char*)ba - 0x02000000);
663
664 test = RCrt(ba, CRT_ID_SYSTEM_CONFIG);
665 test = test | 0x01; /* enable enhanced register access */
666 test = test & 0xEF; /* clear bit 4, 0 wait state */
667 WCrt(ba, CRT_ID_SYSTEM_CONFIG, test);
668
669 /*
670 * bit 1=1: enable enhanced mode functions
671 * bit 4=1: enable linear addressing
672 * bit 5=1: enable MMIO
673 */
674 vgaw(ba, ECR_ADV_FUNC_CNTL, 0x31);
675
676 /* enable color mode (bit0), CPU access (bit1), high 64k page (bit5) */
677 vgaw(ba, GREG_MISC_OUTPUT_W, 0xe3);
678
679 /* CPU base addr */
680 WCrt(ba, CRT_ID_EXT_SYS_CNTL_4, 0x00);
681
682 /* Reset. This does nothing, but everyone does it:) */
683 WSeq(ba, SEQ_ID_RESET, 0x03);
684
685 WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x01); /* 8 Dot Clock */
686 WSeq(ba, SEQ_ID_MAP_MASK, 0x0f); /* Enable write planes */
687 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00); /* Character Font */
688
689 WSeq(ba, SEQ_ID_MEMORY_MODE, 0x02); /* Complete mem access */
690
691 WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x06); /* Unlock extensions */
692 test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL); /* Bus Request */
693
694 /* enable 4MB fast Page Mode */
695 test = test | 1 << 6;
696 WSeq(ba, SEQ_ID_BUS_REQ_CNTL, test);
697 /* faster LUT write */
698 WSeq(ba, SEQ_ID_RAMDAC_CNTL, 0xC0);
699
700 test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2); /* Clksyn2 read */
701
702 /* immediately Clkload bit clear */
703 test = test & 0xDF;
704
705 /* 2 MCLK Memory Write.... */
706 if (cv_memclk >= 55000000)
707 test |= 0x80;
708
709 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test);
710
711 /* Memory CLK */
712 clockpar = cv_compute_clock(cv_memclk);
713 test = (clockpar & 0xFF00) >> 8;
714 WSeq(ba, SEQ_ID_MCLK_HI, test); /* PLL N-Divider Value */
715
716 test = clockpar & 0xFF;
717 WSeq(ba, SEQ_ID_MCLK_LO, test); /* PLL M-Divider Value */
718
719 if (RCrt(ba, CRT_ID_REVISION) == 0x10) /* bugfix for new S3 chips */
720 WSeq(ba, SEQ_ID_MORE_MAGIC, test);
721
722 /* We now load an 25 MHz, 31 kHz, 640x480 standard VGA Mode. */
723 /* DCLK */
724 WSeq(ba, SEQ_ID_DCLK_HI, 0x13);
725 WSeq(ba, SEQ_ID_DCLK_LO, 0x41);
726
727 test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2);
728 test = test | 0x22;
729
730 /* DCLK + MCLK Clock immediate load! */
731 WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test);
732
733 /* DCLK load */
734 test = vgar(ba, 0x3cc);
735 test = test | 0x0c;
736 vgaw(ba, 0x3c2, test);
737
738 /* Clear bit 5 again, prevent further loading. */
739 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x02);
740
741 WCrt(ba, CRT_ID_HOR_TOTAL, 0x5F);
742 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, 0x4F);
743 WCrt(ba, CRT_ID_START_HOR_BLANK, 0x50);
744 WCrt(ba, CRT_ID_END_HOR_BLANK, 0x82);
745 WCrt(ba, CRT_ID_START_HOR_RETR, 0x54);
746 WCrt(ba, CRT_ID_END_HOR_RETR, 0x80);
747 WCrt(ba, CRT_ID_VER_TOTAL, 0xBF);
748
749 WCrt(ba, CRT_ID_OVERFLOW, 0x1F); /* overflow reg */
750
751 WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00); /* no panning */
752
753 WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40); /* vscan */
754
755 WCrt(ba, CRT_ID_CURSOR_START, 0x00);
756 WCrt(ba, CRT_ID_CURSOR_END, 0x00);
757
758 /* Display start address */
759 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
760 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
761
762 /* Cursor location */
763 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
764 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
765
766 /* Vertical retrace */
767 WCrt(ba, CRT_ID_START_VER_RETR, 0x9C);
768 WCrt(ba, CRT_ID_END_VER_RETR, 0x0E);
769
770 WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F);
771 WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50);
772
773 WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00);
774
775 WCrt(ba, CRT_ID_START_VER_BLANK, 0x96);
776 WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9);
777
778 WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3);
779
780 WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF);
781
782 WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */
783
784 /* Refresh count 1, High speed text font, enhanced color mode */
785 WCrt(ba, CRT_ID_MISC_1, 0x35);
786
787 /* start fifo position */
788 WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5a);
789
790 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x70);
791
792 /* address window position */
793 WCrt(ba, CRT_ID_LAW_POS_LO, 0x40);
794
795 /* N Parameter for Display FIFO */
796 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
797
798 WGfx(ba, GCT_ID_SET_RESET, 0x00);
799 WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00);
800 WGfx(ba, GCT_ID_COLOR_COMPARE, 0x00);
801 WGfx(ba, GCT_ID_DATA_ROTATE, 0x00);
802 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
803 WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
804 WGfx(ba, GCT_ID_MISC, 0x01);
805 WGfx(ba, GCT_ID_COLOR_XCARE, 0x0F);
806 WGfx(ba, GCT_ID_BITMASK, 0xFF);
807
808 /* colors for text mode */
809 for (i = 0; i <= 0xf; i++)
810 WAttr (ba, i, i);
811
812 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x41);
813 WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x01);
814 WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0F);
815 WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00);
816 WAttr(ba, ACT_ID_COLOR_SELECT, 0x00);
817
818 vgaw(ba, VDAC_MASK, 0xFF); /* DAC Mask */
819
820 *((volatile unsigned long *)((volatile char*)ba + ECR_FRGD_COLOR)) = 0xFF;
821 *((volatile unsigned long *)((volatile char*)ba + ECR_BKGD_COLOR)) = 0;
822
823 /* colors initially set to greyscale */
824
825 vgaw(ba, VDAC_ADDRESS_W, 0);
826 for (i = 255; i >= 0 ; i--) {
827 vgaw(ba, VDAC_DATA, i);
828 vgaw(ba, VDAC_DATA, i);
829 vgaw(ba, VDAC_DATA, i);
830 }
831
832 /* GFx hardware cursor off */
833 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
834
835 /* Set first to 4 MB, so test will work */
836 WCrt(ba, CRT_ID_LAW_CNTL, 0x13);
837
838 /* find *correct* fbsize of z3 board */
839 if (cv_has_4mb((volatile char *)cv_boardaddr + 0x01400000)) {
840 cv_fbsize = 1024 * 1024 * 4;
841 WCrt(ba, CRT_ID_LAW_CNTL, 0x13); /* 4 MB */
842 } else {
843 cv_fbsize = 1024 * 1024 * 2;
844 WCrt(ba, CRT_ID_LAW_CNTL, 0x12); /* 2 MB */
845 }
846
847 /* Initialize graphics engine */
848 GfxBusyWait(ba);
849 vgaw16(ba, ECR_FRGD_MIX, 0x27);
850 vgaw16(ba, ECR_BKGD_MIX, 0x07);
851
852 vgaw16(ba, ECR_READ_REG_DATA, 0x1000);
853 delay(200000);
854 vgaw16(ba, ECR_READ_REG_DATA, 0x2000);
855 GfxBusyWait(ba);
856 vgaw16(ba, ECR_READ_REG_DATA, 0x3fff);
857 GfxBusyWait(ba);
858 delay(200000);
859 vgaw16(ba, ECR_READ_REG_DATA, 0x4fff);
860 GfxBusyWait(ba);
861
862 vgaw16(ba, ECR_BITPLANE_WRITE_MASK, ~0);
863
864 GfxBusyWait (ba);
865 vgaw16(ba, ECR_READ_REG_DATA, 0xe000);
866 vgaw16(ba, ECR_CURRENT_Y_POS2, 0x00);
867 vgaw16(ba, ECR_CURRENT_X_POS2, 0x00);
868 vgaw16(ba, ECR_READ_REG_DATA, 0xa000);
869 vgaw16(ba, ECR_DEST_Y__AX_STEP, 0x00);
870 vgaw16(ba, ECR_DEST_Y2__AX_STEP2, 0x00);
871 vgaw16(ba, ECR_DEST_X__DIA_STEP, 0x00);
872 vgaw16(ba, ECR_DEST_X2__DIA_STEP2, 0x00);
873 vgaw16(ba, ECR_SHORT_STROKE, 0x00);
874 vgaw16(ba, ECR_DRAW_CMD, 0x01);
875 GfxBusyWait (ba);
876
877 /* It ain't easy to write here, so let's do it again */
878 vgaw16(ba, ECR_READ_REG_DATA, 0x4fff);
879
880 vgaw16(ba, ECR_BKGD_COLOR, 0x01);
881 vgaw16(ba, ECR_FRGD_COLOR, 0x00);
882
883 /* Enable Video Display (Set Bit 5) */
884 WAttr(ba, 0x33, 0);
885
886 gi = &gp->g_display;
887 gi->gd_regaddr = (void *) kvtop (__UNVOLATILE(ba));
888 gi->gd_regsize = 64 * 1024;
889 gi->gd_fbaddr = (void *) kvtop (__UNVOLATILE(gp->g_fbkva));
890 gi->gd_fbsize = cv_fbsize;
891 }
892
893
894 int
895 cv_getvmode(struct grf_softc *gp, struct grfvideo_mode *vm)
896 {
897 struct grfvideo_mode *gv;
898
899 #ifdef CV64CONSOLE
900 /* Handle grabbing console mode */
901 if (vm->mode_num == 255) {
902 memcpy(vm, &cvconsole_mode, sizeof(struct grfvideo_mode));
903 /* XXX so grfconfig can tell us the correct text dimensions. */
904 vm->depth = cvconsole_mode.fy;
905 } else
906 #endif
907 {
908 if (vm->mode_num == 0)
909 vm->mode_num = (monitor_current - monitor_def) + 1;
910 if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
911 return (EINVAL);
912 gv = monitor_def + (vm->mode_num - 1);
913 if (gv->mode_num == 0)
914 return (EINVAL);
915
916 memcpy(vm, gv, sizeof(struct grfvideo_mode));
917 }
918
919 /* adjust internal values to pixel values */
920
921 vm->hblank_start *= 8;
922 vm->hsync_start *= 8;
923 vm->hsync_stop *= 8;
924 vm->htotal *= 8;
925
926 return (0);
927 }
928
929
930 int
931 cv_setvmode(struct grf_softc *gp, unsigned mode)
932 {
933
934 if (!mode || (mode > monitor_def_max) ||
935 monitor_def[mode - 1].mode_num == 0)
936 return (EINVAL);
937
938 monitor_current = monitor_def + (mode - 1);
939
940 return (0);
941 }
942
943
944 int
945 cv_blank(struct grf_softc *gp, int *on)
946 {
947 volatile void *ba;
948
949 ba = gp->g_regkva;
950 gfx_on_off(*on > 0 ? 0 : 1, ba);
951 return (0);
952 }
953
954
955 /*
956 * Change the mode of the display.
957 * Return a UNIX error number or 0 for success.
958 */
959 int
960 cv_mode(register struct grf_softc *gp, u_long cmd, void *arg, u_long a2,
961 int a3)
962 {
963 int error;
964
965 switch (cmd) {
966 case GM_GRFON:
967 error = cv_load_mon (gp,
968 (struct grfcvtext_mode *) monitor_current) ? 0 : EINVAL;
969 return (error);
970
971 case GM_GRFOFF:
972 #ifndef CV64CONSOLE
973 cvscreen(1, (volatile char *)gp->g_regkva - 0x02000000);
974 #else
975 cv_load_mon(gp, &cvconsole_mode);
976 #if NITE > 0
977 ite_reinit(gp->g_itedev);
978 #endif
979 #endif /* CV64CONSOLE */
980 return (0);
981
982 case GM_GRFCONFIG:
983 return (0);
984
985 case GM_GRFGETVMODE:
986 return (cv_getvmode (gp, (struct grfvideo_mode *) arg));
987
988 case GM_GRFSETVMODE:
989 error = cv_setvmode (gp, *(unsigned *) arg);
990 if (!error && (gp->g_flags & GF_GRFON))
991 cv_load_mon(gp,
992 (struct grfcvtext_mode *) monitor_current);
993 return (error);
994
995 case GM_GRFGETNUMVM:
996 *(int *)arg = monitor_def_max;
997 return (0);
998
999 case GM_GRFIOCTL:
1000 return (cv_ioctl (gp, a2, arg));
1001
1002 default:
1003 break;
1004 }
1005
1006 return (EPASSTHROUGH);
1007 }
1008
1009
1010 int
1011 cv_ioctl(register struct grf_softc *gp, u_long cmd, void *data)
1012 {
1013 switch (cmd) {
1014 #ifndef CV_NO_HARDWARE_CURSOR
1015 case GRFIOCGSPRITEPOS:
1016 return(cv_getspritepos (gp, (struct grf_position *) data));
1017
1018 case GRFIOCSSPRITEPOS:
1019 return(cv_setspritepos (gp, (struct grf_position *) data));
1020
1021 case GRFIOCSSPRITEINF:
1022 return(cv_setspriteinfo (gp, (struct grf_spriteinfo *) data));
1023
1024 case GRFIOCGSPRITEINF:
1025 return(cv_getspriteinfo (gp, (struct grf_spriteinfo *) data));
1026
1027 case GRFIOCGSPRITEMAX:
1028 return(cv_getspritemax (gp, (struct grf_position *) data));
1029 #else /* !CV_NO_HARDWARE_CURSOR */
1030 case GRFIOCGSPRITEPOS:
1031 case GRFIOCSSPRITEPOS:
1032 case GRFIOCSSPRITEINF:
1033 case GRFIOCGSPRITEINF:
1034 case GRFIOCGSPRITEMAX:
1035 break;
1036 #endif /* !CV_NO_HARDWARE_CURSOR */
1037
1038 case GRFIOCGETCMAP:
1039 return (cv_getcmap (gp, (struct grf_colormap *) data));
1040
1041 case GRFIOCPUTCMAP:
1042 return (cv_putcmap (gp, (struct grf_colormap *) data));
1043
1044 case GRFIOCBITBLT:
1045 break;
1046
1047 case GRFTOGGLE:
1048 return (cv_toggle (gp));
1049
1050 case GRFIOCSETMON:
1051 return (cv_setmonitor (gp, (struct grfvideo_mode *)data));
1052
1053 case GRFIOCBLANK:
1054 return (cv_blank (gp, (int *)data));
1055 }
1056 return (EPASSTHROUGH);
1057 }
1058
1059
1060 int
1061 cv_setmonitor(struct grf_softc *gp, struct grfvideo_mode *gv)
1062 {
1063 struct grfvideo_mode *md;
1064
1065 if (!cv_mondefok(gv))
1066 return (EINVAL);
1067
1068 #ifdef CV64CONSOLE
1069 /* handle interactive setting of console mode */
1070 if (gv->mode_num == 255) {
1071 memcpy(&cvconsole_mode.gv, gv, sizeof(struct grfvideo_mode));
1072 cvconsole_mode.gv.hblank_start /= 8;
1073 cvconsole_mode.gv.hsync_start /= 8;
1074 cvconsole_mode.gv.hsync_stop /= 8;
1075 cvconsole_mode.gv.htotal /= 8;
1076 cvconsole_mode.rows = gv->disp_height / cvconsole_mode.fy;
1077 cvconsole_mode.cols = gv->disp_width / cvconsole_mode.fx;
1078 if (!(gp->g_flags & GF_GRFON))
1079 cv_load_mon(gp, &cvconsole_mode);
1080 #if NITE > 0
1081 ite_reinit(gp->g_itedev);
1082 #endif
1083 return (0);
1084 }
1085 #endif
1086
1087 md = monitor_def + (gv->mode_num - 1);
1088
1089 /*
1090 * Prevent user from crashing the system by using
1091 * grfconfig while in X
1092 */
1093 if (gp->g_flags & GF_GRFON)
1094 if (md == monitor_current) {
1095 printf("grfcv: Changing the used mode not allowed!\n");
1096 return (EINVAL);
1097 }
1098
1099 memcpy(md, gv, sizeof(struct grfvideo_mode));
1100
1101 /* adjust pixel oriented values to internal rep. */
1102
1103 md->hblank_start /= 8;
1104 md->hsync_start /= 8;
1105 md->hsync_stop /= 8;
1106 md->htotal /= 8;
1107
1108 return (0);
1109 }
1110
1111
1112 int
1113 cv_getcmap(struct grf_softc *gfp, struct grf_colormap *cmap)
1114 {
1115 volatile void *ba;
1116 u_char red[256], green[256], blue[256], *rp, *gp, *bp;
1117 short x;
1118 int error;
1119
1120 ba = gfp->g_regkva;
1121 if (cmap->count == 0 || cmap->index >= 256)
1122 return (0);
1123
1124 if (cmap->count > 256 - cmap->index)
1125 cmap->count = 256 - cmap->index;
1126
1127 /* first read colors out of the chip, then copyout to userspace */
1128 vgaw (ba, VDAC_ADDRESS_W, cmap->index);
1129 x = cmap->count - 1;
1130
1131 rp = red + cmap->index;
1132 gp = green + cmap->index;
1133 bp = blue + cmap->index;
1134
1135 do {
1136 *rp++ = vgar (ba, VDAC_DATA) << 2;
1137 *gp++ = vgar (ba, VDAC_DATA) << 2;
1138 *bp++ = vgar (ba, VDAC_DATA) << 2;
1139 } while (x-- > 0);
1140
1141 if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
1142 && !(error = copyout (green + cmap->index, cmap->green, cmap->count))
1143 && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
1144 return (0);
1145
1146 return (error);
1147 }
1148
1149
1150 int
1151 cv_putcmap(struct grf_softc *gfp, struct grf_colormap *cmap)
1152 {
1153 volatile void *ba;
1154 u_char red[256], green[256], blue[256], *rp, *gp, *bp;
1155 short x;
1156 int error;
1157
1158 ba = gfp->g_regkva;
1159 if (cmap->count == 0 || cmap->index >= 256)
1160 return (0);
1161
1162 if (cmap->count > 256 - cmap->index)
1163 cmap->count = 256 - cmap->index;
1164
1165 /* first copy the colors into kernelspace */
1166 if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
1167 && !(error = copyin (cmap->green, green + cmap->index, cmap->count))
1168 && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) {
1169 vgaw (ba, VDAC_ADDRESS_W, cmap->index);
1170 x = cmap->count - 1;
1171
1172 rp = red + cmap->index;
1173 gp = green + cmap->index;
1174 bp = blue + cmap->index;
1175
1176 do {
1177 vgaw (ba, VDAC_DATA, *rp++ >> 2);
1178 vgaw (ba, VDAC_DATA, *gp++ >> 2);
1179 vgaw (ba, VDAC_DATA, *bp++ >> 2);
1180 } while (x-- > 0);
1181 return (0);
1182 } else
1183 return (error);
1184 }
1185
1186
1187 int
1188 cv_toggle(struct grf_softc *gp)
1189 {
1190 volatile void *ba;
1191
1192 ba = gp->g_regkva;
1193 #ifndef CV64CONSOLE
1194 cv_pass_toggle = 1;
1195 #endif /* !CV64CONSOLE */
1196
1197 if (cv_pass_toggle) {
1198 cvscreen(0, (volatile char*)ba - 0x02000000);
1199 cv_pass_toggle = 0;
1200 } else {
1201 cvscreen(1, (volatile char*)ba - 0x02000000);
1202 cv_pass_toggle = 1;
1203 }
1204
1205 return (0);
1206 }
1207
1208
1209 int
1210 cv_mondefok(struct grfvideo_mode *gv)
1211 {
1212 unsigned long maxpix;
1213
1214 if (gv->mode_num < 1 || gv->mode_num > monitor_def_max) {
1215 if (gv->mode_num != 255 || gv->depth != 4)
1216 return (0);
1217 }
1218
1219 switch(gv->depth) {
1220 case 4:
1221 maxpix = MAXPIXELCLOCK - 55000000;
1222 break;
1223 case 8:
1224 maxpix = MAXPIXELCLOCK;
1225 break;
1226 case 15:
1227 case 16:
1228 #ifdef CV_AGGRESSIVE_TIMING
1229 maxpix = MAXPIXELCLOCK - 35000000;
1230 #else
1231 maxpix = MAXPIXELCLOCK - 55000000;
1232 #endif
1233 break;
1234 case 24:
1235 case 32:
1236 #ifdef CV_AGGRESSIVE_TIMING
1237 maxpix = MAXPIXELCLOCK - 75000000;
1238 #else
1239 maxpix = MAXPIXELCLOCK - 85000000;
1240 #endif
1241 break;
1242 default:
1243 printf("grfcv: Illegal depth in mode %d\n",
1244 (int) gv->mode_num);
1245 return (0);
1246 }
1247
1248 if (gv->pixel_clock > maxpix) {
1249 printf("grfcv: Pixelclock too high in mode %d\n",
1250 (int) gv->mode_num);
1251 return (0);
1252 }
1253
1254 if (gv->mode_num == 255) { /* console mode */
1255 if ((gv->disp_width / 8) > MAXCOLS) {
1256 printf ("grfcv: Too many columns for console\n");
1257 return (0);
1258 } else if ((gv->disp_height / S3FONTY) > MAXROWS) {
1259 printf ("grfcv: Too many rows for console\n");
1260 return (0);
1261 }
1262 }
1263
1264 if (gv->disp_flags & GRF_FLAGS_SYNC_ON_GREEN) {
1265 printf("grfcv: sync-on-green is not supported\n");
1266 return (0);
1267 }
1268
1269 return (1);
1270 }
1271
1272
1273 int
1274 cv_load_mon(struct grf_softc *gp, struct grfcvtext_mode *md)
1275 {
1276 struct grfvideo_mode *gv;
1277 struct grfinfo *gi;
1278 volatile void *ba, *fb;
1279 unsigned short mnr;
1280 unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
1281 VSE, VT;
1282 int cr50, sr15, sr18, clock_mode, test;
1283 int m, n; /* For calc'ing display FIFO */
1284 int tfillm, temptym; /* FIFO fill and empty mclk's */
1285 int hmul; /* Multiplier for hor. Values */
1286 unsigned char hvsync_pulse;
1287 char TEXT, CONSOLE;
1288
1289 /* identity */
1290 gv = &md->gv;
1291
1292 TEXT = (gv->depth == 4);
1293 CONSOLE = (gv->mode_num == 255);
1294
1295 if (!cv_mondefok(gv)) {
1296 printf("grfcv: Monitor definition not ok\n");
1297 return (0);
1298 }
1299
1300 ba = gp->g_regkva;
1301 fb = gp->g_fbkva;
1302
1303 /* Disable Interrupts */
1304 test = RCrt(ba, CRT_ID_BACKWAD_COMP_1);
1305 test &= ~0x10;
1306 WCrt(ba, CRT_ID_BACKWAD_COMP_1, test);
1307
1308 /* turn gfx off, don't mess up the display */
1309 gfx_on_off(1, ba);
1310
1311 /* provide all needed information in grf device-independent locations */
1312 gp->g_data = (void *) gv;
1313 gi = &gp->g_display;
1314 gi->gd_colors = 1 << gv->depth;
1315 gi->gd_planes = gv->depth;
1316 gi->gd_fbwidth = gv->disp_width;
1317 gi->gd_fbheight = gv->disp_height;
1318 gi->gd_fbx = 0;
1319 gi->gd_fby = 0;
1320 if (CONSOLE) {
1321 gi->gd_dwidth = md->fx * md->cols;
1322 gi->gd_dheight = md->fy * md->rows;
1323 } else {
1324 gi->gd_dwidth = gv->disp_width;
1325 gi->gd_dheight = gv->disp_height;
1326 }
1327 gi->gd_dx = 0;
1328 gi->gd_dy = 0;
1329
1330 /* get display mode parameters */
1331 switch (gv->depth) {
1332 case 15:
1333 case 16:
1334 hmul = 2;
1335 break;
1336 default:
1337 hmul = 1;
1338 break;
1339 }
1340
1341 HBS = gv->hblank_start * hmul;
1342 HSS = gv->hsync_start * hmul;
1343 HSE = gv->hsync_stop * hmul;
1344 HBE = gv->htotal * hmul - 6;
1345 HT = gv->htotal * hmul - 5;
1346 VBS = gv->vblank_start - 1;
1347 VSS = gv->vsync_start;
1348 VSE = gv->vsync_stop;
1349 VBE = gv->vtotal - 3;
1350 VT = gv->vtotal - 2;
1351
1352 /* Disable enhanced Mode for text display */
1353
1354 vgaw(ba, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
1355
1356 if (TEXT)
1357 HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
1358 else
1359 HDE = (gv->disp_width + 3) * hmul / 8 - 1; /*HBS;*/
1360 VDE = gv->disp_height - 1;
1361
1362 /* adjustments */
1363
1364 if (gv->disp_flags & GRF_FLAGS_LACE) {
1365 VDE = VDE / 2;
1366 VBS = VBS / 2;
1367 VSS = VSS / 2;
1368 VSE = VSE / 2;
1369 VBE = VBE / 2;
1370 VT = VT / 2;
1371 }
1372
1373 /* Horizontal/Vertical Sync Pulse */
1374 /*
1375 * GREG_MISC_OUTPUT_W Register:
1376 * bit description (0/1)
1377 * 0 Monochrome/Color emulation
1378 * 1 Disable/Enable access of the display memory from the CPU
1379 * 5 Select the low/high 64K page of memory
1380 * 6 Select a positive/negative horizontal retrace sync pulse
1381 * 7 Select a positive/negative vertical retrace sync pulse
1382 */
1383 hvsync_pulse = vgar(ba, GREG_MISC_OUTPUT_R);
1384 if (gv->disp_flags & GRF_FLAGS_PHSYNC)
1385 hvsync_pulse &= ~0x40;
1386 else
1387 hvsync_pulse |= 0x40;
1388 if (gv->disp_flags & GRF_FLAGS_PVSYNC)
1389 hvsync_pulse &= ~0x80;
1390 else
1391 hvsync_pulse |= 0x80;
1392 vgaw(ba, GREG_MISC_OUTPUT_W, hvsync_pulse);
1393
1394 /* GFX hardware cursor off */
1395 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
1396 WCrt(ba, CRT_ID_EXT_DAC_CNTL, 0x00);
1397
1398 WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
1399 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
1400 WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
1401 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
1402
1403 /* Set clock */
1404
1405 mnr = cv_compute_clock(gv->pixel_clock);
1406 WSeq(ba, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
1407 WSeq(ba, SEQ_ID_DCLK_LO, (mnr & 0xFF));
1408
1409 /* load display parameters into board */
1410
1411 WCrt(ba, CRT_ID_EXT_HOR_OVF,
1412 ((HT & 0x100) ? 0x01 : 0x00) |
1413 ((HDE & 0x100) ? 0x02 : 0x00) |
1414 ((HBS & 0x100) ? 0x04 : 0x00) |
1415 /* ((HBE & 0x40) ? 0x08 : 0x00) | */ /* Later... */
1416 ((HSS & 0x100) ? 0x10 : 0x00) |
1417 /* ((HSE & 0x20) ? 0x20 : 0x00) | */
1418 (((HT-5) & 0x100) ? 0x40 : 0x00) );
1419
1420 WCrt(ba, CRT_ID_EXT_VER_OVF,
1421 0x40 | /* Line compare */
1422 ((VT & 0x400) ? 0x01 : 0x00) |
1423 ((VDE & 0x400) ? 0x02 : 0x00) |
1424 ((VBS & 0x400) ? 0x04 : 0x00) |
1425 ((VSS & 0x400) ? 0x10 : 0x00) );
1426
1427 WCrt(ba, CRT_ID_HOR_TOTAL, HT);
1428 WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5);
1429
1430 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
1431 WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
1432 WCrt(ba, CRT_ID_END_HOR_BLANK, ((HBE & 0x1f) | 0x80));
1433 WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
1434 WCrt(ba, CRT_ID_END_HOR_RETR,
1435 (HSE & 0x1f) |
1436 ((HBE & 0x20) ? 0x80 : 0x00) );
1437 WCrt(ba, CRT_ID_VER_TOTAL, VT);
1438 WCrt(ba, CRT_ID_OVERFLOW,
1439 0x10 |
1440 ((VT & 0x100) ? 0x01 : 0x00) |
1441 ((VDE & 0x100) ? 0x02 : 0x00) |
1442 ((VSS & 0x100) ? 0x04 : 0x00) |
1443 ((VBS & 0x100) ? 0x08 : 0x00) |
1444 ((VT & 0x200) ? 0x20 : 0x00) |
1445 ((VDE & 0x200) ? 0x40 : 0x00) |
1446 ((VSS & 0x200) ? 0x80 : 0x00) );
1447
1448 WCrt(ba, CRT_ID_MAX_SCAN_LINE,
1449 0x40 | /* TEXT ? 0x00 ??? */
1450 ((gv->disp_flags & GRF_FLAGS_DBLSCAN) ? 0x80 : 0x00) |
1451 ((VBS & 0x200) ? 0x20 : 0x00) |
1452 (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
1453
1454 WCrt(ba, CRT_ID_MODE_CONTROL, 0xe3);
1455
1456 /* text cursor */
1457
1458 if (TEXT) {
1459 #if CV_ULCURSOR
1460 WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
1461 WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
1462 #else
1463 WCrt(ba, CRT_ID_CURSOR_START, 0x00);
1464 WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
1465 #endif
1466 WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f);
1467
1468 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1469 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
1470 }
1471
1472 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
1473 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
1474
1475 WCrt(ba, CRT_ID_START_VER_RETR, VSS);
1476 WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f));
1477 WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
1478 WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
1479 WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
1480
1481 WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
1482 WCrt(ba, CRT_ID_LACE_RETR_START, HT / 2);
1483 WCrt(ba, CRT_ID_LACE_CONTROL,
1484 ((gv->disp_flags & GRF_FLAGS_LACE) ? 0x20 : 0x00));
1485
1486 WGfx(ba, GCT_ID_GRAPHICS_MODE,
1487 ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
1488 WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
1489
1490 WSeq (ba, SEQ_ID_MEMORY_MODE,
1491 ((TEXT || (gv->depth == 1)) ? 0x06 : 0x02));
1492
1493 vgaw(ba, VDAC_MASK, 0xff);
1494
1495 /* Blank border */
1496 test = RCrt(ba, CRT_ID_BACKWAD_COMP_2);
1497 WCrt(ba, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
1498
1499 sr15 = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);
1500 sr15 &= ~0x10;
1501 sr18 = RSeq(ba, SEQ_ID_RAMDAC_CNTL);
1502 sr18 &= ~0x80;
1503 clock_mode = 0x00;
1504 cr50 = 0x00;
1505
1506 test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2);
1507 test &= 0xd;
1508
1509 /* clear roxxler byte-swapping... */
1510 cv_write_port(0x0040, cv_boardaddr);
1511 cv_write_port(0x0020, cv_boardaddr);
1512
1513 switch (gv->depth) {
1514 case 1:
1515 case 4: /* text */
1516 HDE = gv->disp_width / 16;
1517 break;
1518 case 8:
1519 if (gv->pixel_clock > 80000000) {
1520 clock_mode = 0x10 | 0x02;
1521 sr15 |= 0x10;
1522 sr18 |= 0x80;
1523 }
1524 HDE = gv->disp_width / 8;
1525 cr50 |= 0x00;
1526 break;
1527 case 15:
1528 cv_write_port (0x8020, cv_boardaddr);
1529 clock_mode = 0x30;
1530 HDE = gv->disp_width / 4;
1531 cr50 |= 0x10;
1532 break;
1533 case 16:
1534 cv_write_port (0x8020, cv_boardaddr);
1535 clock_mode = 0x50;
1536 HDE = gv->disp_width / 4;
1537 cr50 |= 0x10;
1538 break;
1539 case 24: /* this is really 32 Bit on CV64 */
1540 case 32:
1541 cv_write_port(0x8040, cv_boardaddr);
1542 clock_mode = 0xd0;
1543 HDE = (gv->disp_width / 2);
1544 cr50 |= 0x30;
1545 break;
1546 }
1547
1548 WCrt(ba, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
1549 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, sr15);
1550 WSeq(ba, SEQ_ID_RAMDAC_CNTL, sr18);
1551 WCrt(ba, CRT_ID_SCREEN_OFFSET, HDE);
1552
1553 WCrt(ba, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
1554
1555 test = RCrt(ba, CRT_ID_EXT_SYS_CNTL_2);
1556 test &= ~0x30;
1557 /* HDE Overflow in bits 4-5 */
1558 test |= (HDE >> 4) & 0x30;
1559 WCrt(ba, CRT_ID_EXT_SYS_CNTL_2, test);
1560
1561 /* Set up graphics engine */
1562 switch (gv->disp_width) {
1563 case 1024:
1564 cr50 |= 0x00;
1565 break;
1566 case 640:
1567 cr50 |= 0x40;
1568 break;
1569 case 800:
1570 cr50 |= 0x80;
1571 break;
1572 case 1280:
1573 cr50 |= 0xc0;
1574 break;
1575 case 1152:
1576 cr50 |= 0x01;
1577 break;
1578 case 1600:
1579 cr50 |= 0x81;
1580 break;
1581 default: /* XXX The Xserver has to handle this */
1582 break;
1583 }
1584
1585 WCrt(ba, CRT_ID_EXT_SYS_CNTL_1, cr50);
1586
1587 delay(100000);
1588 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
1589 delay(100000);
1590 WAttr(ba, ACT_ID_COLOR_PLANE_ENA,
1591 (gv->depth == 1) ? 0x01 : 0x0f);
1592 delay(100000);
1593
1594 /*
1595 * M-Parameter of Display FIFO
1596 * This is dependent on the pixel clock and the memory clock.
1597 * The FIFO filling bandwidth is 240 MHz and the FIFO is 96 Byte wide.
1598 * Then the time to fill the FIFO is tfill = (96/240000000) sec, the time
1599 * to empty the FIFO is tempty = (96/pixelclock) sec.
1600 * Then the M parameter maximum is ((tempty-tfill)*cv_memclk-9)/2.
1601 * This seems to be logical, ain't it?
1602 * Remember: We have to use integer arithmetics :(
1603 * Divide by 1000 to prevent overflows.
1604 */
1605
1606 tfillm = (96 * (cv_memclk/1000))/240000;
1607
1608 switch(gv->depth) {
1609 case 32:
1610 case 24:
1611 temptym = (24 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
1612 break;
1613 case 15:
1614 case 16:
1615 temptym = (48 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
1616 break;
1617 case 4:
1618 temptym = (192 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
1619 break;
1620 default:
1621 temptym = (96 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
1622 break;
1623 }
1624
1625 m = (temptym - tfillm - 9) / 2;
1626 if (m < 0)
1627 m = 0; /* prevent underflow */
1628 m = (m & 0x1f) << 3;
1629 if (m < 0x18)
1630 m = 0x18;
1631 n = 0xff;
1632
1633 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, m);
1634 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, n);
1635 delay(10000);
1636
1637 /* text initialization */
1638
1639 if (TEXT) {
1640 cv_inittextmode(gp);
1641 }
1642
1643 if (CONSOLE) {
1644 int i;
1645 vgaw(ba, VDAC_ADDRESS_W, 0);
1646 for (i = 0; i < 16; i++) {
1647 vgaw(ba, VDAC_DATA, cvconscolors[i][0]);
1648 vgaw(ba, VDAC_DATA, cvconscolors[i][1]);
1649 vgaw(ba, VDAC_DATA, cvconscolors[i][2]);
1650 }
1651 }
1652
1653 /* Set display enable flag */
1654 WAttr(ba, 0x33, 0);
1655
1656 /* turn gfx on again */
1657 gfx_on_off(0, ba);
1658
1659 /* enable interrupts */
1660 test = RCrt(ba, CRT_ID_BACKWAD_COMP_1);
1661 test |= 0x10;
1662 WCrt(ba, CRT_ID_BACKWAD_COMP_1, test);
1663
1664 test = RCrt(ba, CRT_ID_END_VER_RETR);
1665 test &= ~0x20;
1666 WCrt(ba, CRT_ID_END_VER_RETR, test);
1667 test &= ~0x10;
1668 WCrt(ba, CRT_ID_END_VER_RETR, test);
1669 test |= 0x10;
1670 WCrt(ba, CRT_ID_END_VER_RETR, test);
1671 #ifndef CV_NO_HARDWARE_CURSOR
1672 cv_setup_hwc(gp);
1673 #endif
1674
1675 /* Pass-through */
1676 cvscreen(0, (volatile char*)ba - 0x02000000);
1677
1678 return (1);
1679 }
1680
1681
1682 void
1683 cv_inittextmode(struct grf_softc *gp)
1684 {
1685 struct grfcvtext_mode *tm = (struct grfcvtext_mode *)gp->g_data;
1686 volatile void *ba, *fb;
1687 volatile unsigned char *c;
1688 unsigned char *f, y;
1689 unsigned short z;
1690
1691 ba = gp->g_regkva;
1692 fb = gp->g_fbkva;
1693
1694 /* load text font into beginning of display memory.
1695 * Each character cell is 32 bytes long (enough for 4 planes)
1696 * In linear addressing text mode, the memory is organized
1697 * so, that the Bytes of all 4 planes are interleaved.
1698 * 1st byte plane 0, 1st byte plane 1, 1st byte plane 2,
1699 * 1st byte plane 3, 2nd byte plane 0, 2nd byte plane 1,...
1700 * The font is loaded in plane 2.
1701 */
1702
1703 c = (volatile unsigned char *) fb;
1704
1705 /* clear screen */
1706 for (z = 0; z < tm->cols * tm->rows * 3; z++) {
1707 *c++ = 0x20;
1708 *c++ = 0x07;
1709 *c++ = 0;
1710 *c++ = 0;
1711 }
1712
1713 c = (volatile unsigned char *)fb + (32 * tm->fdstart * 4 + 2);
1714 f = tm->fdata;
1715 for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy) * 4)
1716 for (y = 0; y < tm->fy; y++) {
1717 *c = *f++;
1718 c += 4;
1719 }
1720
1721 /* print out a little init msg */
1722 c = (volatile unsigned char *)fb + (tm->cols - 6) * 4;
1723 *c++ = 'C';
1724 *c++ = 0x0a;
1725 c +=2;
1726 *c++ = 'V';
1727 *c++ = 0x0b;
1728 c +=2;
1729 *c++ = '6';
1730 *c++ = 0x0c;
1731 c +=2;
1732 *c++ = '4';
1733 *c++ = 0x0d;
1734 }
1735
1736
1737 static inline void
1738 cv_write_port(unsigned short bits, volatile void *BoardAddr)
1739 {
1740 volatile char *addr;
1741 static unsigned char CVPortBits = 0; /* mirror port bits here */
1742
1743 addr = (volatile char*)BoardAddr + 0x40001;
1744 if (bits & 0x8000)
1745 CVPortBits |= bits & 0xFF; /* Set bits */
1746 else {
1747 bits = bits & 0xFF;
1748 bits = (~bits) & 0xFF ;
1749 CVPortBits &= bits; /* Clear bits */
1750 }
1751
1752 *addr = CVPortBits;
1753 }
1754
1755
1756 /*
1757 * Monitor Switch
1758 * 0 = CyberVision Signal
1759 * 1 = Amiga Signal,
1760 * ba = boardaddr
1761 */
1762 static inline void
1763 cvscreen(int toggle, volatile void *ba)
1764 {
1765
1766 if (toggle == 1)
1767 cv_write_port (0x10, ba);
1768 else
1769 cv_write_port (0x8010, ba);
1770 }
1771
1772
1773 /* 0 = on, 1= off */
1774 /* ba= registerbase */
1775 static inline void
1776 gfx_on_off(int toggle, volatile void *ba)
1777 {
1778 int r;
1779
1780 toggle &= 0x1;
1781 toggle = toggle << 5;
1782
1783 r = RSeq(ba, SEQ_ID_CLOCKING_MODE);
1784 r &= ~0x20; /* set Bit 5 to 0 */
1785
1786 WSeq(ba, SEQ_ID_CLOCKING_MODE, r | toggle);
1787 }
1788
1789
1790 #ifndef CV_NO_HARDWARE_CURSOR
1791
1792 static unsigned char cv_hotx = 0, cv_hoty = 0;
1793 static char cv_cursor_on = 0;
1794
1795 /* Hardware Cursor handling routines */
1796
1797 int
1798 cv_getspritepos(struct grf_softc *gp, struct grf_position *pos)
1799 {
1800 int hi,lo;
1801 volatile void *ba = gp->g_regkva;
1802
1803 hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI);
1804 lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO);
1805
1806 pos->y = (hi << 8) + lo;
1807 hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI);
1808 lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO);
1809 pos->x = (hi << 8) + lo;
1810 return (0);
1811 }
1812
1813
1814 int
1815 cv_setspritepos(struct grf_softc *gp, struct grf_position *pos)
1816 {
1817 volatile void *ba = gp->g_regkva;
1818 short x, y;
1819 static short savex, savey;
1820 short xoff, yoff;
1821
1822 if (pos) {
1823 x = pos->x;
1824 y = pos->y;
1825 savex = x;
1826 savey= y;
1827 } else { /* restore cursor */
1828 x = savex;
1829 y = savey;
1830 }
1831 x -= cv_hotx;
1832 y -= cv_hoty;
1833 if (x < 0) {
1834 xoff = ((-x) & 0xFE);
1835 x = 0;
1836 } else {
1837 xoff = 0;
1838 }
1839
1840 if (y < 0) {
1841 yoff = ((-y) & 0xFE);
1842 y = 0;
1843 } else {
1844 yoff = 0;
1845 }
1846
1847 WCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI, (x >> 8));
1848 WCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO, (x & 0xff));
1849
1850 WCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO, (y & 0xff));
1851 WCrt(ba, CRT_ID_HWGC_DSTART_X, xoff);
1852 WCrt(ba, CRT_ID_HWGC_DSTART_Y, yoff);
1853 WCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI, (y >> 8));
1854
1855 return(0);
1856 }
1857
1858 static inline short
1859 M2I(short val)
1860 {
1861 return ( ((val & 0xff00) >> 8) | ((val & 0xff) << 8));
1862 }
1863
1864 int
1865 cv_getspriteinfo(struct grf_softc *gp, struct grf_spriteinfo *info)
1866 {
1867 volatile void *ba, *fb;
1868
1869 ba = gp->g_regkva;
1870 fb = gp->g_fbkva;
1871
1872 if (info->set & GRFSPRSET_ENABLE)
1873 info->enable = RCrt(ba, CRT_ID_HWGC_MODE) & 0x01;
1874
1875 if (info->set & GRFSPRSET_POS)
1876 cv_getspritepos (gp, &info->pos);
1877
1878 #if 0 /* XXX */
1879 if (info->set & GRFSPRSET_SHAPE) {
1880 u_char image[512], mask[512];
1881 volatile u_long *hwp;
1882 u_char *imp, *mp;
1883 short row;
1884 info->size.x = 64;
1885 info->size.y = 64;
1886 for (row = 0, hwp = (u_long *)(fb + HWC_OFF),
1887 mp = mask, imp = image;
1888 row < 64;
1889 row++) {
1890 u_long bp10, bp20, bp11, bp21;
1891 bp10 = *hwp++;
1892 bp20 = *hwp++;
1893 bp11 = *hwp++;
1894 bp21 = *hwp++;
1895 M2I (bp10);
1896 M2I (bp20);
1897 M2I (bp11);
1898 M2I (bp21);
1899 *imp++ = (~bp10) & bp11;
1900 *imp++ = (~bp20) & bp21;
1901 *mp++ = (~bp10) | (bp10 & ~bp11);
1902 *mp++ = (~bp20) & (bp20 & ~bp21);
1903 }
1904 copyout (image, info->image, sizeof (image));
1905 copyout (mask, info->mask, sizeof (mask));
1906 }
1907 #endif
1908 return(0);
1909 }
1910
1911
1912 void
1913 cv_setup_hwc(struct grf_softc *gp)
1914 {
1915 volatile void *ba = gp->g_regkva;
1916 volatile char *hwc;
1917 int test;
1918
1919 if (gp->g_display.gd_planes <= 4)
1920 cv_cursor_on = 0; /* don't enable hwc in text modes */
1921 if (cv_cursor_on == 0)
1922 return;
1923
1924 /* reset colour stack */
1925 #if !defined(__m68k__)
1926 test = RCrt(ba, CRT_ID_HWGC_MODE);
1927 amiga_cpu_sync();
1928 #else
1929 /* do it in assembler, the above does't seem to work */
1930 __asm volatile ("moveb #0x45, %1@(0x3d4); \
1931 moveb %1@(0x3d5),%0" : "=d" (test) : "a" (ba));
1932 #endif
1933
1934 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
1935
1936 hwc = (volatile char*)ba + CRT_ADDRESS_W;
1937 *hwc = 0;
1938 *hwc = 0;
1939
1940 #if !defined(__m68k__)
1941 test = RCrt(ba, CRT_ID_HWGC_MODE);
1942 amiga_cpu_sync();
1943 #else
1944 /* do it in assembler, the above does't seem to work */
1945 __asm volatile ("moveb #0x45, %1@(0x3d4); \
1946 moveb %1@(0x3d5),%0" : "=d" (test) : "a" (ba));
1947 #endif
1948 switch (gp->g_display.gd_planes) {
1949 case 8:
1950 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0x1);
1951 *hwc = 1;
1952 break;
1953 default:
1954 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
1955 *hwc = 0xff;
1956 *hwc = 0xff;
1957 }
1958
1959 test = HWC_OFF / HWC_SIZE;
1960 WCrt (ba, CRT_ID_HWGC_START_AD_HI, (test >> 8));
1961 WCrt (ba, CRT_ID_HWGC_START_AD_LO, (test & 0xff));
1962
1963 WCrt (ba, CRT_ID_HWGC_DSTART_X , 0);
1964 WCrt (ba, CRT_ID_HWGC_DSTART_Y , 0);
1965
1966 WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x10); /* Cursor X11 Mode */
1967 /*
1968 * Put it into Windoze Mode or you'll see sometimes a white stripe
1969 * on the right side (in double clocking modes with a screen bigger
1970 * > 1023 pixels).
1971 */
1972 WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x00); /* Cursor Windoze Mode */
1973
1974 WCrt (ba, CRT_ID_HWGC_MODE, 0x01);
1975 }
1976
1977
1978 /*
1979 * This was the reason why you shouldn't use the HWC in the Kernel:(
1980 * Obsoleted now by use of interrupts :-)
1981 */
1982
1983 #define VerticalRetraceWait(ba) \
1984 { \
1985 while (vgar(ba, GREG_INPUT_STATUS1_R) == 0x00) ; \
1986 while ((vgar(ba, GREG_INPUT_STATUS1_R) & 0x08) == 0x08) ; \
1987 while ((vgar(ba, GREG_INPUT_STATUS1_R) & 0x08) == 0x00) ; \
1988 }
1989
1990
1991 int
1992 cv_setspriteinfo(struct grf_softc *gp, struct grf_spriteinfo *info)
1993 {
1994 volatile void *ba, *fb;
1995 int depth = gp->g_display.gd_planes;
1996
1997 ba = gp->g_regkva;
1998 fb = gp->g_fbkva;
1999
2000 if (info->set & GRFSPRSET_SHAPE) {
2001 /*
2002 * For an explanation of these weird actions here, see above
2003 * when reading the shape. We set the shape directly into
2004 * the video memory, there's no reason to keep 1k on the
2005 * kernel stack just as template
2006 */
2007 u_char *image, *mask;
2008 volatile u_short *hwp;
2009 u_char *imp, *mp;
2010 unsigned short row;
2011
2012 #ifdef CV_NO_INT
2013 /* Cursor off */
2014 WCrt (ba, CRT_ID_HWGC_MODE, 0x00);
2015
2016 /*
2017 * The Trio64 crashes if the cursor data is written
2018 * while the cursor is displayed.
2019 * Sadly, turning the cursor off is not enough.
2020 * What we have to do is:
2021 * 1. Wait for vertical retrace, to make sure no-one
2022 * has moved the cursor in this sync period (because
2023 * another write then would have no effect, argh!).
2024 * 2. Move the cursor off-screen
2025 * 3. Another wait for v. retrace to make sure the cursor
2026 * is really off.
2027 * 4. Write the data, finally.
2028 * (thanks to Harald Koenig for this tip!)
2029 */
2030
2031 /*
2032 * Remark 06/06/96: Update in interrupt obsoletes this,
2033 * but the warning should stay there!
2034 */
2035
2036 VerticalRetraceWait(ba);
2037
2038 WCrt (ba, CRT_ID_HWGC_ORIGIN_X_HI, 0x7);
2039 WCrt (ba, CRT_ID_HWGC_ORIGIN_X_LO, 0xff);
2040 WCrt (ba, CRT_ID_HWGC_ORIGIN_Y_LO, 0xff);
2041 WCrt (ba, CRT_ID_HWGC_DSTART_X, 0x3f);
2042 WCrt (ba, CRT_ID_HWGC_DSTART_Y, 0x3f);
2043 WCrt (ba, CRT_ID_HWGC_ORIGIN_Y_HI, 0x7);
2044 #endif /* CV_NO_INT */
2045
2046 if (info->size.y > 64)
2047 info->size.y = 64;
2048 if (info->size.x > 64)
2049 info->size.x = 64;
2050 if (info->size.x < 32)
2051 info->size.x = 32;
2052
2053 image = malloc(HWC_SIZE, M_TEMP, M_WAITOK);
2054 mask = image + HWC_SIZE/2;
2055
2056 copyin(info->image, image, info->size.y * info->size.x / 8);
2057 copyin(info->mask, mask, info->size.y * info->size.x / 8);
2058
2059 #ifdef CV_NO_INT
2060 hwp = (u_short *)(fb +HWC_OFF);
2061
2062 /* This is necessary in order not to crash the board */
2063 VerticalRetraceWait(ba);
2064 #else /* CV_NO_INT */
2065 hwp = (u_short *) cv_cursor_storage;
2066 #endif /* CV_NO_INT */
2067
2068 /*
2069 * setting it is slightly more difficult, because we can't
2070 * force the application to not pass a *smaller* than
2071 * supported bitmap
2072 */
2073
2074 for (row = 0, mp = mask, imp = image;
2075 row < info->size.y; row++) {
2076 u_short im1, im2, im3, im4, m1, m2, m3, m4;
2077
2078 m1 = ~(*(unsigned short *)mp);
2079 im1 = *(unsigned short *)imp & *(unsigned short *)mp;
2080 mp += 2;
2081 imp += 2;
2082
2083 m2 = ~(*(unsigned short *)mp);
2084 im2 = *(unsigned short *)imp & *(unsigned short *)mp;
2085 mp += 2;
2086 imp += 2;
2087
2088 if (info->size.x > 32) {
2089 m3 = ~(*(unsigned short *)mp);
2090 im3 = *(unsigned short *)imp & *(unsigned short *)mp;
2091 mp += 2;
2092 imp += 2;
2093 m4 = ~(*(unsigned short *)mp);
2094 im4 = *(unsigned short *)imp & *(unsigned short *)mp;
2095 mp += 2;
2096 imp += 2;
2097 } else {
2098 m3 = 0xffff;
2099 im3 = 0;
2100 m4 = 0xffff;
2101 im4 = 0;
2102 }
2103
2104 switch (depth) {
2105 case 8:
2106 *hwp++ = m1;
2107 *hwp++ = im1;
2108 *hwp++ = m2;
2109 *hwp++ = im2;
2110 *hwp++ = m3;
2111 *hwp++ = im3;
2112 *hwp++ = m4;
2113 *hwp++ = im4;
2114 break;
2115 case 15:
2116 case 16:
2117 *hwp++ = M2I(m1);
2118 *hwp++ = M2I(im1);
2119 *hwp++ = M2I(m2);
2120 *hwp++ = M2I(im2);
2121 *hwp++ = M2I(m3);
2122 *hwp++ = M2I(im3);
2123 *hwp++ = M2I(m4);
2124 *hwp++ = M2I(im4);
2125 break;
2126 case 24:
2127 case 32:
2128 *hwp++ = M2I(im1);
2129 *hwp++ = M2I(m1);
2130 *hwp++ = M2I(im2);
2131 *hwp++ = M2I(m2);
2132 *hwp++ = M2I(im3);
2133 *hwp++ = M2I(m3);
2134 *hwp++ = M2I(im4);
2135 *hwp++ = M2I(m4);
2136 break;
2137 }
2138 }
2139
2140 if (depth < 24) {
2141 for (; row < 64; row++) {
2142 *hwp++ = 0xffff;
2143 *hwp++ = 0x0000;
2144 *hwp++ = 0xffff;
2145 *hwp++ = 0x0000;
2146 *hwp++ = 0xffff;
2147 *hwp++ = 0x0000;
2148 *hwp++ = 0xffff;
2149 *hwp++ = 0x0000;
2150 }
2151 } else {
2152 for (; row < 64; row++) {
2153 *hwp++ = 0x0000;
2154 *hwp++ = 0xffff;
2155 *hwp++ = 0x0000;
2156 *hwp++ = 0xffff;
2157 *hwp++ = 0x0000;
2158 *hwp++ = 0xffff;
2159 *hwp++ = 0x0000;
2160 *hwp++ = 0xffff;
2161 }
2162 }
2163
2164 free(image, M_TEMP);
2165 /* cv_setup_hwc(gp); */
2166 cv_hotx = info->hot.x;
2167 cv_hoty = info->hot.y;
2168
2169 #ifdef CV_NO_INT
2170 /* One must not write twice per vertical blank :-( */
2171 VerticalRetraceWait(ba);
2172 cv_setspritepos (gp, &info->pos);
2173 #else /* CV_NO_INT */
2174 cv_setspritepos (gp, &info->pos);
2175 curs_update_flag = 1;
2176 #endif /* CV_NO_INT */
2177 }
2178 if (info->set & GRFSPRSET_CMAP) {
2179 volatile char *hwc;
2180 int test;
2181
2182 /* reset colour stack */
2183 test = RCrt(ba, CRT_ID_HWGC_MODE);
2184 amiga_cpu_sync();
2185 switch (depth) {
2186 case 8:
2187 case 15:
2188 case 16:
2189 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
2190 hwc = (volatile char*)ba + CRT_ADDRESS_W;
2191 *hwc = 0;
2192 break;
2193 case 32:
2194 case 24:
2195 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
2196 hwc = (volatile char*)ba + CRT_ADDRESS_W;
2197 *hwc = 0;
2198 *hwc = 0;
2199 break;
2200 }
2201
2202 test = RCrt(ba, CRT_ID_HWGC_MODE);
2203 amiga_cpu_sync();
2204 switch (depth) {
2205 case 8:
2206 WCrt (ba, CRT_ID_HWGC_BG_STACK, 1);
2207 hwc = (volatile char*)ba + CRT_ADDRESS_W;
2208 *hwc = 1;
2209 break;
2210 case 15:
2211 case 16:
2212 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
2213 hwc = (volatile char*)ba + CRT_ADDRESS_W;
2214 *hwc = 0xff;
2215 break;
2216 case 32:
2217 case 24:
2218 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
2219 hwc = (volatile char*)ba + CRT_ADDRESS_W;
2220 *hwc = 0xff;
2221 *hwc = 0xff;
2222 break;
2223 }
2224 }
2225
2226 if (info->set & GRFSPRSET_ENABLE) {
2227 if (info->enable) {
2228 cv_cursor_on = 1;
2229 cv_setup_hwc(gp);
2230 /* WCrt(ba, CRT_ID_HWGC_MODE, 0x01); */
2231 } else
2232 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
2233 }
2234 if (info->set & GRFSPRSET_POS)
2235 cv_setspritepos(gp, &info->pos);
2236 if (info->set & GRFSPRSET_HOT) {
2237
2238 cv_hotx = info->hot.x;
2239 cv_hoty = info->hot.y;
2240 cv_setspritepos (gp, &info->pos);
2241 }
2242 return(0);
2243 }
2244
2245
2246 int
2247 cv_getspritemax (struct grf_softc *gp, struct grf_position *pos)
2248 {
2249
2250 pos->x = 64;
2251 pos->y = 64;
2252 return(0);
2253 }
2254
2255 #endif /* !CV_NO_HARDWARE_CURSOR */
2256
2257 #if NWSDISPLAY > 0
2258
2259 static void
2260 cv_wscursor(void *c, int on, int row, int col)
2261 {
2262 struct rasops_info *ri;
2263 struct vcons_screen *scr;
2264 struct grf_softc *gp;
2265 volatile void *ba;
2266 int offs;
2267
2268 ri = c;
2269 scr = ri->ri_hw;
2270 gp = scr->scr_cookie;
2271 ba = gp->g_regkva;
2272
2273 if ((ri->ri_flg & RI_CURSOR) && !on) {
2274 /* cursor was visible, but we want to remove it */
2275 /*WCrt(ba, CRT_ID_CURSOR_START, | 0x20);*/
2276 ri->ri_flg &= ~RI_CURSOR;
2277 }
2278
2279 ri->ri_crow = row;
2280 ri->ri_ccol = col;
2281
2282 if (on) {
2283 /* move cursor to new location */
2284 if (!(ri->ri_flg & RI_CURSOR)) {
2285 /*WCrt(ba, CRT_ID_CURSOR_START, | 0x20);*/
2286 ri->ri_flg |= RI_CURSOR;
2287 }
2288 offs = gp->g_rowoffset[row] + col;
2289 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, offs & 0xff);
2290 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, offs >> 8);
2291 }
2292 }
2293
2294 static void cv_wsputchar(void *c, int row, int col, u_int ch, long attr)
2295 {
2296 struct rasops_info *ri;
2297 struct vcons_screen *scr;
2298 struct grf_softc *gp;
2299 volatile unsigned char *cp;
2300
2301 ri = c;
2302 scr = ri->ri_hw;
2303 gp = scr->scr_cookie;
2304 cp = gp->g_fbkva;
2305 cp += (gp->g_rowoffset[row] + col) << 2;
2306 *cp++ = ch;
2307 *cp = attr;
2308 }
2309
2310 static void
2311 cv_wscopycols(void *c, int row, int srccol, int dstcol, int ncols)
2312 {
2313 struct rasops_info *ri;
2314 struct vcons_screen *scr;
2315 struct grf_softc *gp;
2316 volatile uint16_t *src, *dst;
2317
2318 KASSERT(ncols > 0);
2319 ri = c;
2320 scr = ri->ri_hw;
2321 gp = scr->scr_cookie;
2322 src = dst = gp->g_fbkva;
2323 src += (gp->g_rowoffset[row] + srccol) << 1;
2324 dst += (gp->g_rowoffset[row] + dstcol) << 1;
2325 if (src < dst) {
2326 /* need to copy backwards */
2327 src += (ncols - 1) << 1;
2328 dst += (ncols - 1) << 1;
2329 while (ncols--) {
2330 *dst = *src;
2331 src -= 2;
2332 dst -= 2;
2333 }
2334 } else
2335 while (ncols--) {
2336 *dst = *src;
2337 src += 2;
2338 dst += 2;
2339 }
2340 }
2341
2342 static void
2343 cv_wserasecols(void *c, int row, int startcol, int ncols, long fillattr)
2344 {
2345 struct rasops_info *ri;
2346 struct vcons_screen *scr;
2347 struct grf_softc *gp;
2348 volatile uint16_t *cp;
2349 uint16_t val;
2350
2351 ri = c;
2352 scr = ri->ri_hw;
2353 gp = scr->scr_cookie;
2354 cp = gp->g_fbkva;
2355 val = 0x2000 | fillattr;
2356 cp += (gp->g_rowoffset[row] + startcol) << 1;
2357 while (ncols--) {
2358 *cp = val;
2359 cp += 2;
2360 }
2361 }
2362
2363 static void
2364 cv_wscopyrows(void *c, int srcrow, int dstrow, int nrows)
2365 {
2366 struct rasops_info *ri;
2367 struct vcons_screen *scr;
2368 struct grf_softc *gp;
2369 volatile uint16_t *src, *dst;
2370 int n;
2371
2372 KASSERT(nrows > 0);
2373 ri = c;
2374 scr = ri->ri_hw;
2375 gp = scr->scr_cookie;
2376 src = dst = gp->g_fbkva;
2377 n = ri->ri_cols * nrows;
2378 if (src < dst) {
2379 /* need to copy backwards */
2380 src += gp->g_rowoffset[srcrow + nrows] << 1;
2381 dst += gp->g_rowoffset[dstrow + nrows] << 1;
2382 while (n--) {
2383 src -= 2;
2384 dst -= 2;
2385 *dst = *src;
2386 }
2387 } else {
2388 src += gp->g_rowoffset[srcrow] << 1;
2389 dst += gp->g_rowoffset[dstrow] << 1;
2390 while (n--) {
2391 *dst = *src;
2392 src += 2;
2393 dst += 2;
2394 }
2395 }
2396 }
2397
2398 static void
2399 cv_wseraserows(void *c, int row, int nrows, long fillattr)
2400 {
2401 struct rasops_info *ri;
2402 struct vcons_screen *scr;
2403 struct grf_softc *gp;
2404 volatile uint16_t *cp;
2405 int n;
2406 uint16_t val;
2407
2408 ri = c;
2409 scr = ri->ri_hw;
2410 gp = scr->scr_cookie;
2411 cp = gp->g_fbkva;
2412 val = 0x2000 | fillattr;
2413 cp += gp->g_rowoffset[row] << 1;
2414 n = ri->ri_cols * nrows;
2415 while (n--) {
2416 *cp = val;
2417 cp += 2;
2418 }
2419 }
2420
2421 static int
2422 cv_wsallocattr(void *c, int fg, int bg, int flg, long *attr)
2423 {
2424
2425 /* XXX color support? */
2426 *attr = (flg & WSATTR_REVERSE) ? 0x70 : 0x07;
2427 if (flg & WSATTR_UNDERLINE) *attr = 0x01;
2428 if (flg & WSATTR_HILIT) *attr |= 0x08;
2429 if (flg & WSATTR_BLINK) *attr |= 0x80;
2430 return 0;
2431 }
2432
2433 /* our font does not support unicode extensions */
2434 static int
2435 cv_wsmapchar(void *c, int ch, unsigned int *cp)
2436 {
2437
2438 if (ch > 0 && ch < 256) {
2439 *cp = ch;
2440 return 5;
2441 }
2442 *cp = ' ';
2443 return 0;
2444 }
2445
2446 #endif /* NWSDISPLAY > 0 */
2447
2448 #endif /* NGRFCV */
2449