1/* $NetBSD: grf_cv.c,v 1.52 2011/06/30 20:09:19 wiz 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 2011/06/30 20:09:19 wiz 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 83int grfcvmatch(struct device *, struct cfdata *, void *); 84void grfcvattach(struct device *, struct device *, void *); 85int grfcvprint(void *, const char *); 86 87int cvintr(void *); 88static int cv_has_4mb(volatile void *); 89static unsigned short cv_compute_clock(unsigned long); 90void cv_boardinit(struct grf_softc *); 91int cv_getvmode(struct grf_softc *, struct grfvideo_mode *); 92int cv_setvmode(struct grf_softc *, unsigned int); 93int cv_blank(struct grf_softc *, int *); 94int cv_mode(register struct grf_softc *, u_long, void *, u_long, int); 95int cv_ioctl(register struct grf_softc *gp, u_long cmd, void *data); 96int cv_setmonitor(struct grf_softc *, struct grfvideo_mode *); 97int cv_getcmap(struct grf_softc *, struct grf_colormap *); 98int cv_putcmap(struct grf_softc *, struct grf_colormap *); 99int cv_toggle(struct grf_softc *); 100int cv_mondefok(struct grfvideo_mode *); 101int cv_load_mon(struct grf_softc *, struct grfcvtext_mode *); 102void cv_inittextmode(struct grf_softc *); 103static inline void cv_write_port(unsigned short, volatile void *); 104static inline void cvscreen(int, volatile void *); 105static inline void gfx_on_off(int, volatile void *); 106 107#ifndef CV_NO_HARDWARE_CURSOR 108int cv_getspritepos(struct grf_softc *, struct grf_position *); 109int cv_setspritepos(struct grf_softc *, struct grf_position *); 110int cv_getspriteinfo(struct grf_softc *,struct grf_spriteinfo *); 111void cv_setup_hwc(struct grf_softc *); 112int cv_setspriteinfo(struct grf_softc *,struct grf_spriteinfo *); 113int 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 120struct 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 129static 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}; 134static struct grfvideo_mode *monitor_current = &monitor_def[0]; 135#define MAXPIXELCLOCK 135000000 /* safety */ 136 137unsigned 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 153extern unsigned char S3FONT[]; 154 155/* 156 * Define default console mode 157 * (Internally, we still have to use hvalues/8!) 158 */ 159struct 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 */ 166unsigned 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 186static unsigned char clocks[]={ 1870x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69, 1880x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c, 1890x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a, 1900x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69, 1910x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65, 1920x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63, 1930x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d, 1940x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49, 1950x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42, 1960x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43, 1970x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49, 1980x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a, 1990x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49, 2000x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41, 2010x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43, 2020x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45, 2030x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45, 2040x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45, 2050x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44, 2060x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46, 2070x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f, 2080x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22, 2090x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46, 2100x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b, 2110x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44, 2120x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26, 2130x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b, 2140x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25, 2150x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25, 2160x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21, 2170x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29, 2180x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29, 2190x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29, 2200x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28, 2210x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26, 2220x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21, 2230x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28, 2240x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27, 2250x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22, 2260x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27, 2270x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27, 2280x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21, 2290x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26, 2300x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27, 2310x13, 0x1, 0x13, 0x1, 0x7d, 0x27, 0x4c, 0x9, 2320x37, 0x22, 0x5b, 0xb, 0x71, 0x26, 0x5c, 0xb, 2330x6b, 0xd, 0x47, 0x23, 0x14, 0x1, 0x4f, 0x9, 2340x23, 0x3, 0x75, 0x26, 0x7d, 0xf, 0x1c, 0x2, 2350x51, 0x9, 0x59, 0x24, 0x61, 0xb, 0x69, 0x25, 2360x79, 0x26, 0x34, 0x5, 0x1d, 0x2, 0x6b, 0x25, 2370x54, 0x9, 0x35, 0x5, 0x45, 0x7, 0x6d, 0x25, 2380x7d, 0x26, 0x16, 0x1, 0x7f, 0x26, 0x77, 0xd, 2390x4f, 0x23, 0x78, 0xd, 0x2f, 0x21, 0x27, 0x3, 2400x1f, 0x2, 0x59, 0x9, 0x6a, 0xb, 0x73, 0x25, 2410x6b, 0xb, 0x63, 0x24, 0x5b, 0x9, 0x20, 0x2, 2420x7e, 0xd, 0x4b, 0x7, 0x65, 0x24, 0x43, 0x22, 2430x18, 0x1, 0x6f, 0xb, 0x5e, 0x9, 0x70, 0xb, 2440x2a, 0x3, 0x33, 0x4, 0x45, 0x6, 0x60, 0x9, 2450x7b, 0xc, 0x19, 0x1, 0x19, 0x1, 0x7d, 0xc, 2460x74, 0xb, 0x50, 0x7, 0x75, 0xb, 0x63, 0x9, 2470x51, 0x7, 0x23, 0x2, 0x3f, 0x5, 0x1a, 0x1, 2480x65, 0x9, 0x2d, 0x3, 0x40, 0x5, 0x0, 0x0, 249}; 250 251 252/* Board Address of CV64 */ 253static volatile void *cv_boardaddr; 254static 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 266long cv_memclk = 55000000; 267#else 268long cv_memclk = 50000000; 269#endif 270 271#if NWSDISPLAY > 0 272/* wsdisplay acessops, emulops */ 273static void cv_wscursor(void *, int, int, int); 274static void cv_wsputchar(void *, int, int, u_int, long); 275static void cv_wscopycols(void *, int, int, int, int); 276static void cv_wserasecols(void *, int, int, int, long); 277static void cv_wscopyrows(void *, int, int, int); 278static void cv_wseraserows(void *, int, int, long); 279static int cv_wsallocattr(void *, int, int, int, long *); 280static int cv_wsmapchar(void *, int, unsigned int *); 281 282static struct wsdisplay_accessops cv_accessops = { 283 .ioctl = grf_wsioctl, 284 .mmap = grf_wsmmap 285}; 286 287static 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 298static 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 309static 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 */ 320CFATTACH_DECL(grfcv, sizeof(struct grf_cv_softc), 321 grfcvmatch, grfcvattach, NULL, NULL); 322 323static 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 333static unsigned short cv_cursor_storage[HWC_SIZE/2]; 334static 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 346int 347cvintr(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 */ 412static int 413cv_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 443int 444grfcvmatch(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 475void 476grfcvattach(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 563int 564grfcvprint(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 583static unsigned short 584cv_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 625void 626cv_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 894int 895cv_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 930int 931cv_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 944int 945cv_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 */ 959int 960cv_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 1010int 1011cv_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 1060int 1061cv_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 1112int 1113cv_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 1150int 1151cv_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 1187int 1188cv_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 1209int 1210cv_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 1273int 1274cv_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 1682void 1683cv_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 1737static inline void 1738cv_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 */ 1762static inline void 1763cvscreen(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 */ 1775static inline void 1776gfx_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 1792static unsigned char cv_hotx = 0, cv_hoty = 0; 1793static char cv_cursor_on = 0; 1794 1795/* Hardware Cursor handling routines */ 1796 1797int 1798cv_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 1814int 1815cv_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 1858static inline short 1859M2I(short val) 1860{ 1861 return ( ((val & 0xff00) >> 8) | ((val & 0xff) << 8)); 1862} 1863 1864int 1865cv_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 1912void 1913cv_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 1991int 1992cv_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 2246int 2247cv_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 2259static void 2260cv_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 2294static 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 2310static void 2311cv_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 2342static void 2343cv_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 2363static void 2364cv_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 2398static void 2399cv_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 2421static int 2422cv_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 */ 2434static int 2435cv_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