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