1 /* $NetBSD: stic.c,v 1.54 2019/11/10 21:16:37 chs Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Driver for the DEC PixelStamp interface chip (STIC). 34 * 35 * XXX The bt459 interface shouldn't be replicated here. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: stic.c,v 1.54 2019/11/10 21:16:37 chs Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 #include <sys/buf.h> 47 #include <sys/ioctl.h> 48 #include <sys/callout.h> 49 #include <sys/conf.h> 50 #include <sys/kauth.h> 51 #include <sys/lwp.h> 52 #include <sys/event.h> 53 54 #if defined(pmax) 55 #include <mips/cpuregs.h> 56 #elif defined(alpha) 57 #include <alpha/alpha_cpu.h> 58 #endif 59 60 #include <machine/vmparam.h> 61 #include <sys/bus.h> 62 #include <sys/intr.h> 63 64 #include <dev/wscons/wsconsio.h> 65 #include <dev/wscons/wsdisplayvar.h> 66 67 #include <dev/wsfont/wsfont.h> 68 69 #include <dev/ic/bt459reg.h> 70 71 #include <dev/tc/tcvar.h> 72 #include <dev/tc/sticreg.h> 73 #include <dev/tc/sticio.h> 74 #include <dev/tc/sticvar.h> 75 76 #define DUPBYTE0(x) ((((x)&0xff)<<16) | (((x)&0xff)<<8) | ((x)&0xff)) 77 #define DUPBYTE1(x) ((((x)<<8)&0xff0000) | ((x)&0xff00) | (((x)>>8)&0xff)) 78 #define DUPBYTE2(x) (((x)&0xff0000) | (((x)>>8)&0xff00) | (((x)>>16)&0xff)) 79 80 #define PACK(p, o) ((p)[(o)] | ((p)[(o)+1] << 16)) 81 82 #if defined(pmax) 83 #define machine_btop(x) mips_btop(x) 84 #elif defined(alpha) 85 #define machine_btop(x) alpha_btop(x) 86 #endif 87 88 /* 89 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have 90 * obscure register layout such as 2nd and 3rd Bt459 registers are 91 * adjacent each other in a word, i.e., 92 * struct bt459triplet { 93 * struct { 94 * uint8_t u0; 95 * uint8_t u1; 96 * uint8_t u2; 97 * unsigned :8; 98 * } bt_lo; 99 * struct { 100 * 101 * Although HX has single Bt459, 32bit R/W can be done w/o any trouble. 102 * struct bt459reg { 103 * uint32_t bt_lo; 104 * uint32_t bt_hi; 105 * uint32_t bt_reg; 106 * uint32_t bt_cmap; 107 * }; 108 * 109 */ 110 111 /* Bt459 hardware registers */ 112 #define bt_lo 0 113 #define bt_hi 1 114 #define bt_reg 2 115 #define bt_cmap 3 116 117 #define REG(base, index) *((volatile uint32_t *)(base) + (index)) 118 #define SELECT(vdac, regno) do { \ 119 REG(vdac, bt_lo) = DUPBYTE0(regno); \ 120 REG(vdac, bt_hi) = DUPBYTE1(regno); \ 121 tc_wmb(); \ 122 } while (0) 123 124 static int sticioctl(void *, void *, u_long, void *, int, struct lwp *); 125 static int stic_alloc_screen(void *, const struct wsscreen_descr *, 126 void **, int *, int *, long *); 127 static void stic_free_screen(void *, void *); 128 static int stic_show_screen(void *, void *, int, 129 void (*)(void *, int, int), void *); 130 131 static void stic_do_switch(void *); 132 static void stic_setup_backing(struct stic_info *, struct stic_screen *); 133 static void stic_setup_vdac(struct stic_info *); 134 static void stic_clear_screen(struct stic_info *); 135 136 static int stic_get_cmap(struct stic_info *, struct wsdisplay_cmap *); 137 static int stic_set_cmap(struct stic_info *, struct wsdisplay_cmap *); 138 static int stic_set_cursor(struct stic_info *, struct wsdisplay_cursor *); 139 static int stic_get_cursor(struct stic_info *, struct wsdisplay_cursor *); 140 static void stic_set_curpos(struct stic_info *, struct wsdisplay_curpos *); 141 static void stic_set_hwcurpos(struct stic_info *); 142 143 static void stic_cursor(void *, int, int, int); 144 static void stic_copycols(void *, int, int, int, int); 145 static void stic_copyrows(void *, int, int, int); 146 static void stic_erasecols(void *, int, int, int, long); 147 static void stic_eraserows(void *, int, int, long); 148 static int stic_mapchar(void *, int, u_int *); 149 static void stic_putchar(void *, int, int, u_int, long); 150 static int stic_allocattr(void *, int, int, int, long *); 151 152 static dev_type_open(sticopen); 153 static dev_type_close(sticclose); 154 static dev_type_mmap(sticmmap); 155 156 const struct cdevsw stic_cdevsw = { 157 .d_open = sticopen, 158 .d_close = sticclose, 159 .d_read = noread, 160 .d_write = nowrite, 161 .d_ioctl = noioctl, 162 .d_stop = nostop, 163 .d_tty = notty, 164 .d_poll = nopoll, 165 .d_mmap = sticmmap, 166 .d_kqfilter = nokqfilter, 167 .d_discard = nodiscard, 168 .d_flag = 0 169 }; 170 171 /* Colormap for wscons, matching WSCOL_*. Upper 8 are high-intensity. */ 172 static const uint8_t stic_cmap[16*3] = { 173 0x00, 0x00, 0x00, /* black */ 174 0x7f, 0x00, 0x00, /* red */ 175 0x00, 0x7f, 0x00, /* green */ 176 0x7f, 0x7f, 0x00, /* brown */ 177 0x00, 0x00, 0x7f, /* blue */ 178 0x7f, 0x00, 0x7f, /* magenta */ 179 0x00, 0x7f, 0x7f, /* cyan */ 180 0xc7, 0xc7, 0xc7, /* white */ 181 182 0x7f, 0x7f, 0x7f, /* black */ 183 0xff, 0x00, 0x00, /* red */ 184 0x00, 0xff, 0x00, /* green */ 185 0xff, 0xff, 0x00, /* brown */ 186 0x00, 0x00, 0xff, /* blue */ 187 0xff, 0x00, 0xff, /* magenta */ 188 0x00, 0xff, 0xff, /* cyan */ 189 0xff, 0xff, 0xff, /* white */ 190 }; 191 192 /* 193 * Compose 2 bit/pixel cursor image. Bit order will be reversed. 194 * M M M M I I I I M I M I M I M I 195 * [ before ] [ after ] 196 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3 197 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7 198 */ 199 static const uint8_t shuffle[256] = { 200 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 201 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55, 202 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4, 203 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5, 204 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74, 205 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75, 206 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4, 207 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5, 208 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c, 209 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d, 210 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc, 211 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd, 212 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c, 213 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d, 214 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc, 215 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd, 216 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56, 217 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57, 218 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6, 219 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7, 220 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76, 221 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77, 222 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6, 223 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7, 224 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e, 225 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f, 226 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde, 227 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf, 228 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e, 229 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f, 230 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe, 231 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff, 232 }; 233 234 static const struct wsdisplay_accessops stic_accessops = { 235 sticioctl, 236 NULL, /* mmap */ 237 stic_alloc_screen, 238 stic_free_screen, 239 stic_show_screen, 240 NULL, /* load_font */ 241 }; 242 243 static const struct wsdisplay_emulops stic_emulops = { 244 stic_cursor, 245 stic_mapchar, 246 stic_putchar, 247 stic_copycols, 248 stic_erasecols, 249 stic_copyrows, 250 stic_eraserows, 251 stic_allocattr 252 }; 253 254 static struct wsscreen_descr stic_stdscreen = { 255 "std", 256 0, 0, 257 &stic_emulops, 258 0, 0, 259 WSSCREEN_WSCOLORS | WSSCREEN_HILIT 260 }; 261 262 static const struct wsscreen_descr *_stic_scrlist[] = { 263 &stic_stdscreen, 264 }; 265 266 static const struct wsscreen_list stic_screenlist = { 267 sizeof(_stic_scrlist) / sizeof(struct wsscreen_descr *), _stic_scrlist 268 }; 269 270 struct stic_info stic_consinfo; 271 static struct stic_screen stic_consscr; 272 static struct stic_info *stic_info[STIC_MAXDV]; 273 static int stic_unit; 274 275 void 276 stic_init(struct stic_info *si) 277 { 278 volatile uint32_t *vdac; 279 int i, cookie; 280 281 /* Reset the STIC & stamp(s). */ 282 stic_reset(si); 283 vdac = si->si_vdac; 284 285 /* Hit it... */ 286 SELECT(vdac, BT459_IREG_COMMAND_0); 287 REG(vdac, bt_reg) = 0x00c0c0c0; tc_wmb(); 288 289 /* Now reset the VDAC. */ 290 *si->si_vdac_reset = 0; 291 tc_wmb(); 292 tc_syncbus(); 293 DELAY(1000); 294 295 /* Finish the initialization. */ 296 SELECT(vdac, BT459_IREG_COMMAND_1); 297 REG(vdac, bt_reg) = 0x00000000; tc_wmb(); 298 REG(vdac, bt_reg) = 0x00c2c2c2; tc_wmb(); 299 REG(vdac, bt_reg) = 0x00ffffff; tc_wmb(); 300 301 for (i = 0; i < 7; i++) { 302 REG(vdac, bt_reg) = 0x00000000; 303 tc_wmb(); 304 } 305 306 /* Set cursor colormap. */ 307 SELECT(vdac, BT459_IREG_CCOLOR_1); 308 REG(vdac, bt_reg) = 0x00ffffff; tc_wmb(); 309 REG(vdac, bt_reg) = 0x00ffffff; tc_wmb(); 310 REG(vdac, bt_reg) = 0x00ffffff; tc_wmb(); 311 REG(vdac, bt_reg) = 0x00000000; tc_wmb(); 312 REG(vdac, bt_reg) = 0x00000000; tc_wmb(); 313 REG(vdac, bt_reg) = 0x00000000; tc_wmb(); 314 REG(vdac, bt_reg) = 0x00ffffff; tc_wmb(); 315 REG(vdac, bt_reg) = 0x00ffffff; tc_wmb(); 316 REG(vdac, bt_reg) = 0x00ffffff; tc_wmb(); 317 318 /* Get a font and set up screen metrics. */ 319 wsfont_init(); 320 321 cookie = wsfont_find(NULL, 12, 0, 2, WSDISPLAY_FONTORDER_R2L, 322 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 323 if (cookie <= 0) 324 cookie = wsfont_find(NULL, 0, 0, 2, WSDISPLAY_FONTORDER_R2L, 325 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 326 if (cookie <= 0) 327 panic("stic_init: font table is empty"); 328 329 if (wsfont_lock(cookie, &si->si_font)) 330 panic("stic_init: couldn't lock font"); 331 332 si->si_fontw = si->si_font->fontwidth; 333 si->si_fonth = si->si_font->fontheight; 334 si->si_consw = (1280 / si->si_fontw) & ~1; 335 si->si_consh = 1024 / si->si_fonth; 336 stic_stdscreen.ncols = si->si_consw; 337 stic_stdscreen.nrows = si->si_consh; 338 339 #ifdef DIAGNOSTIC 340 if ((u_int)si->si_fonth > 32 || (u_int)si->si_fontw > 16) 341 panic("stic_init: unusable font"); 342 #endif 343 344 stic_setup_vdac(si); 345 stic_clear_screen(si); 346 si->si_dispmode = WSDISPLAYIO_MODE_EMUL; 347 } 348 349 void 350 stic_reset(struct stic_info *si) 351 { 352 int modtype, xconfig, yconfig, config; 353 volatile struct stic_regs *sr; 354 355 sr = si->si_stic; 356 357 /* 358 * Initialize the interface chip registers. 359 */ 360 sr->sr_sticsr = 0x00000030; /* Get the STIC's attention. */ 361 tc_wmb(); 362 tc_syncbus(); 363 DELAY(2000); /* wait 2ms for STIC to respond. */ 364 sr->sr_sticsr = 0x00000000; /* Hit the STIC's csr again... */ 365 tc_wmb(); 366 sr->sr_buscsr = 0xffffffff; /* and bash its bus-acess csr. */ 367 tc_wmb(); 368 tc_syncbus(); /* Blam! */ 369 DELAY(20000); /* wait until the stic recovers... */ 370 371 modtype = sr->sr_modcl; 372 xconfig = (modtype & 0x800) >> 11; 373 yconfig = (modtype & 0x600) >> 9; 374 config = (yconfig << 1) | xconfig; 375 si->si_stampw = (xconfig ? 5 : 4); 376 si->si_stamph = (1 << yconfig); 377 si->si_stamphm = si->si_stamph - 1; 378 #ifdef notyet 379 si->si_option = (char)((modtype >> 12) & 3); 380 #endif 381 382 /* First PixelStamp */ 383 si->si_stamp[0x000b0] = config; 384 si->si_stamp[0x000b4] = 0x0; 385 386 /* Second PixelStamp */ 387 if (yconfig > 0) { 388 si->si_stamp[0x100b0] = config | 8; 389 si->si_stamp[0x100b4] = 0; 390 } 391 392 /* 393 * Initialize STIC video registers. Enable error and vertical 394 * retrace interrupts. Set the packet done flag so the Xserver will 395 * not time-out on the first packet submitted. 396 */ 397 sr->sr_vblank = (1024 << 16) | 1063; 398 sr->sr_vsync = (1027 << 16) | 1030; 399 sr->sr_hblank = (255 << 16) | 340; 400 sr->sr_hsync2 = 245; 401 sr->sr_hsync = (261 << 16) | 293; 402 sr->sr_ipdvint = 403 STIC_INT_WE | STIC_INT_P | STIC_INT_E_EN | STIC_INT_V_EN; 404 sr->sr_sticsr = 8; 405 tc_wmb(); 406 tc_syncbus(); 407 } 408 409 void 410 stic_attach(device_t self, struct stic_info *si, int console) 411 { 412 struct wsemuldisplaydev_attach_args waa; 413 414 if (stic_unit < STIC_MAXDV) { 415 stic_info[stic_unit] = si; 416 si->si_unit = stic_unit++; 417 } else 418 si->si_unit = -1; 419 420 callout_init(&si->si_switch_callout, 0); 421 422 /* 423 * Allocate backing for the console. We could trawl back through 424 * msgbuf and fill the backing, but it's not worth the hassle. 425 * We could also grab backing using pmap_steal_memory() early on, 426 * but that's a little ugly. 427 */ 428 if (console) 429 stic_setup_backing(si, &stic_consscr); 430 431 waa.console = console; 432 waa.scrdata = &stic_screenlist; 433 waa.accessops = &stic_accessops; 434 waa.accesscookie = si; 435 436 config_found(self, &waa, wsemuldisplaydevprint); 437 } 438 439 void 440 stic_cnattach(struct stic_info *si) 441 { 442 struct stic_screen *ss; 443 long defattr; 444 445 ss = &stic_consscr; 446 si->si_curscreen = ss; 447 ss->ss_flags = SS_ALLOCED | SS_ACTIVE | SS_CURENB; 448 ss->ss_si = si; 449 450 si->si_flags |= SI_CURENB_CHANGED; 451 stic_flush(si); 452 453 stic_allocattr(ss, 0, 0, 0, &defattr); 454 stic_eraserows(ss, 0, si->si_consh, 0); 455 wsdisplay_cnattach(&stic_stdscreen, ss, 0, 0, defattr); 456 } 457 458 static void 459 stic_setup_vdac(struct stic_info *si) 460 { 461 uint8_t *ip, *mp; 462 int r, c, o, b, i, s; 463 464 s = spltty(); 465 466 ip = (uint8_t *)si->si_cursor.cc_image; 467 mp = (uint8_t *)si->si_cursor.cc_mask; 468 memset(ip, 0, sizeof(si->si_cursor.cc_image)); 469 memset(mp, 0, sizeof(si->si_cursor.cc_mask)); 470 471 for (r = 0; r < si->si_fonth; r++) { 472 for (c = r & 1; c < si->si_fontw; c += 2) { 473 o = c >> 3; 474 b = 1 << (c & 7); 475 ip[o] |= b; 476 mp[o] |= b; 477 } 478 479 ip += 8; 480 mp += 8; 481 } 482 483 si->si_cursor.cc_size.x = 64; 484 si->si_cursor.cc_size.y = si->si_fonth; 485 si->si_cursor.cc_hot.x = 0; 486 si->si_cursor.cc_hot.y = 0; 487 488 si->si_cursor.cc_color[0] = 0xff; 489 si->si_cursor.cc_color[2] = 0xff; 490 si->si_cursor.cc_color[4] = 0xff; 491 si->si_cursor.cc_color[1] = 0x00; 492 si->si_cursor.cc_color[3] = 0x00; 493 si->si_cursor.cc_color[5] = 0x00; 494 495 memset(&si->si_cmap, 0, sizeof(si->si_cmap)); 496 for (i = 0; i < 16; i++) { 497 si->si_cmap.r[i] = stic_cmap[i*3 + 0]; 498 si->si_cmap.g[i] = stic_cmap[i*3 + 1]; 499 si->si_cmap.b[i] = stic_cmap[i*3 + 2]; 500 } 501 502 si->si_flags |= SI_CMAP_CHANGED | SI_CURSHAPE_CHANGED | 503 SI_CURCMAP_CHANGED; 504 505 splx(s); 506 } 507 508 static void 509 stic_clear_screen(struct stic_info *si) 510 { 511 uint32_t *pb; 512 int i; 513 514 /* 515 * Do this twice, since the first packet after a reset may be 516 * silently ignored. 517 */ 518 for (i = 0; i < 2; i++) { 519 pb = (*si->si_pbuf_get)(si); 520 521 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET; 522 pb[1] = 0x01ffffff; 523 pb[2] = 0; 524 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY; 525 pb[4] = (1024 << 2) - 1; 526 pb[5] = 0; 527 pb[6] = 0; 528 pb[7] = (1280 << 19) | ((1024 << 3) + pb[4]); 529 530 (*si->si_pbuf_post)(si, pb); 531 } 532 } 533 534 static int 535 sticioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 536 { 537 struct stic_info *si; 538 int s; 539 540 si = v; 541 542 switch (cmd) { 543 case WSDISPLAYIO_GTYPE: 544 *(u_int *)data = si->si_disptype; 545 return (0); 546 547 case WSDISPLAYIO_GINFO: 548 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 549 wsd_fbip->height = 1024; 550 wsd_fbip->width = 1280; 551 wsd_fbip->depth = si->si_depth == 8 ? 8 : 32; 552 wsd_fbip->cmsize = CMAP_SIZE; 553 #undef fbt 554 return (0); 555 556 case WSDISPLAYIO_GETCMAP: 557 return (stic_get_cmap(si, (struct wsdisplay_cmap *)data)); 558 559 case WSDISPLAYIO_PUTCMAP: 560 return (stic_set_cmap(si, (struct wsdisplay_cmap *)data)); 561 562 case WSDISPLAYIO_SVIDEO: 563 #if 0 /* XXX later */ 564 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 565 if ((si->si_blanked == 0) ^ turnoff) 566 si->si_blanked = turnoff; 567 #endif 568 return (0); 569 570 case WSDISPLAYIO_GVIDEO: 571 #if 0 /* XXX later */ 572 *(u_int *)data = si->si_blanked ? 573 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 574 #endif 575 return (0); 576 577 case WSDISPLAYIO_GCURPOS: 578 *(struct wsdisplay_curpos *)data = si->si_cursor.cc_pos; 579 return (0); 580 581 case WSDISPLAYIO_SCURPOS: 582 stic_set_curpos(si, (struct wsdisplay_curpos *)data); 583 return (0); 584 585 case WSDISPLAYIO_GCURMAX: 586 ((struct wsdisplay_curpos *)data)->x = 587 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 588 return (0); 589 590 case WSDISPLAYIO_GCURSOR: 591 return (stic_get_cursor(si, (struct wsdisplay_cursor *)data)); 592 593 case WSDISPLAYIO_SCURSOR: 594 return (stic_set_cursor(si, (struct wsdisplay_cursor *)data)); 595 596 case WSDISPLAYIO_SMODE: 597 si->si_dispmode = *(int *)data; 598 if (si->si_dispmode == WSDISPLAYIO_MODE_EMUL) { 599 (*si->si_ioctl)(si, STICIO_STOPQ, NULL, flag, l); 600 stic_setup_vdac(si); 601 s = spltty(); 602 stic_flush(si); 603 splx(s); 604 stic_clear_screen(si); 605 stic_do_switch(si->si_curscreen); 606 } 607 return (0); 608 609 case STICIO_RESET: 610 stic_reset(si); 611 return (0); 612 } 613 614 if (si->si_ioctl != NULL) 615 return ((*si->si_ioctl)(si, cmd, data, flag, l)); 616 617 return (EPASSTHROUGH); 618 } 619 620 static void 621 stic_setup_backing(struct stic_info *si, struct stic_screen *ss) 622 { 623 int size; 624 625 size = si->si_consw * si->si_consh * sizeof(*ss->ss_backing); 626 ss->ss_backing = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO); 627 } 628 629 static int 630 stic_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 631 int *curxp, int *curyp, long *attrp) 632 { 633 struct stic_info *si; 634 struct stic_screen *ss; 635 636 si = (struct stic_info *)v; 637 638 if ((stic_consscr.ss_flags & SS_ALLOCED) == 0) 639 ss = &stic_consscr; 640 else { 641 ss = malloc(sizeof(*ss), M_DEVBUF, M_WAITOK|M_ZERO); 642 } 643 stic_setup_backing(si, ss); 644 645 ss->ss_si = si; 646 ss->ss_flags = SS_ALLOCED | SS_CURENB; 647 648 *cookiep = ss; 649 *curxp = 0; 650 *curyp = 0; 651 652 stic_allocattr(ss, 0, 0, 0, attrp); 653 return (0); 654 } 655 656 static void 657 stic_free_screen(void *v, void *cookie) 658 { 659 struct stic_screen *ss; 660 661 ss = cookie; 662 663 #ifdef DIAGNOSTIC 664 if (ss == &stic_consscr) 665 panic("stic_free_screen: console"); 666 if (ss == ((struct stic_info *)v)->si_curscreen) 667 panic("stic_free_screen: freeing current screen"); 668 #endif 669 670 free(ss->ss_backing, M_DEVBUF); 671 free(ss, M_DEVBUF); 672 } 673 674 static int 675 stic_show_screen(void *v, void *cookie, int waitok, 676 void (*cb)(void *, int, int), void *cbarg) 677 { 678 struct stic_info *si; 679 680 si = (struct stic_info *)v; 681 if (si->si_switchcbarg != NULL) 682 return (EAGAIN); 683 si->si_switchcb = cb; 684 si->si_switchcbarg = cbarg; 685 686 if (cb != NULL) { 687 callout_reset(&si->si_switch_callout, 0, stic_do_switch, 688 cookie); 689 return (EAGAIN); 690 } 691 692 stic_do_switch(cookie); 693 return (0); 694 } 695 696 static void 697 stic_do_switch(void *cookie) 698 { 699 struct stic_screen *ss; 700 struct stic_info *si; 701 u_int r, c, nr, nc; 702 uint16_t *p, *sp; 703 704 ss = cookie; 705 si = ss->ss_si; 706 707 #ifdef DIAGNOSTIC 708 if (ss->ss_backing == NULL) 709 panic("stic_do_switch: screen not backed"); 710 #endif 711 712 /* Swap in the new screen, and temporarily disable its backing. */ 713 if (si->si_curscreen != NULL) 714 si->si_curscreen->ss_flags ^= SS_ACTIVE; 715 si->si_curscreen = ss; 716 ss->ss_flags |= SS_ACTIVE; 717 sp = ss->ss_backing; 718 ss->ss_backing = NULL; 719 720 /* 721 * We assume that most of the screen is blank and blast it with 722 * eraserows(), because eraserows() is cheap. 723 */ 724 nr = si->si_consh; 725 stic_eraserows(ss, 0, nr, 0); 726 727 nc = si->si_consw; 728 p = sp; 729 for (r = 0; r < nr; r++) 730 for (c = 0; c < nc; c += 2, p += 2) { 731 if ((p[0] & 0xfff0) != 0) 732 stic_putchar(ss, r, c, p[0] >> 8, 733 p[0] & 0x00ff); 734 if ((p[1] & 0xfff0) != 0) 735 stic_putchar(ss, r, c + 1, p[1] >> 8, 736 p[1] & 0x00ff); 737 } 738 739 /* 740 * Re-enable the screen's backing, and move the cursor to the 741 * correct spot. 742 */ 743 ss->ss_backing = sp; 744 si->si_cursor.cc_pos.x = ss->ss_curx; 745 si->si_cursor.cc_pos.y = ss->ss_cury; 746 stic_set_hwcurpos(si); 747 si->si_flags |= SI_CURENB_CHANGED; 748 749 /* 750 * XXX Since we don't yet receive vblank interrupts from the 751 * PXG, we must flush immediately. 752 */ 753 if (si->si_disptype == WSDISPLAY_TYPE_PXG) 754 stic_flush(si); 755 756 /* Tell wscons that we're done. */ 757 if (si->si_switchcbarg != NULL) { 758 cookie = si->si_switchcbarg; 759 si->si_switchcbarg = NULL; 760 (*si->si_switchcb)(cookie, 0, 0); 761 } 762 } 763 764 static int 765 stic_allocattr(void *cookie, int fg, int bg, int flags, long *attr) 766 { 767 long tmp; 768 769 if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0) 770 return (EINVAL); 771 772 if ((flags & WSATTR_WSCOLORS) == 0) { 773 fg = 7; 774 bg = 0; 775 } 776 777 if ((flags & WSATTR_HILIT) != 0) 778 fg += 8; 779 780 tmp = fg | (bg << 4); 781 *attr = tmp | (tmp << 16); 782 return (0); 783 } 784 785 static void 786 stic_erasecols(void *cookie, int row, int col, int num, long attr) 787 { 788 struct stic_info *si; 789 struct stic_screen *ss; 790 uint32_t *pb; 791 u_int i, linewidth; 792 uint16_t *p; 793 794 ss = cookie; 795 si = ss->ss_si; 796 797 if (ss->ss_backing != NULL) { 798 p = ss->ss_backing + row * si->si_consw + col; 799 for (i = num; i != 0; i--) 800 *p++ = (uint16_t)attr; 801 } 802 if ((ss->ss_flags & SS_ACTIVE) == 0) 803 return; 804 805 col = (col * si->si_fontw) << 19; 806 num = (num * si->si_fontw) << 19; 807 row = row * si->si_fonth; 808 attr = (attr & 0xf0) >> 4; 809 linewidth = (si->si_fonth << 2) - 1; 810 row = (row << 3) + linewidth; 811 812 pb = (*si->si_pbuf_get)(si); 813 814 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET; 815 pb[1] = 0x01ffffff; 816 pb[2] = 0; 817 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY; 818 pb[4] = linewidth; 819 pb[5] = DUPBYTE0(attr); 820 pb[6] = col | row; 821 pb[7] = (col + num) | row; 822 823 (*si->si_pbuf_post)(si, pb); 824 } 825 826 static void 827 stic_eraserows(void *cookie, int row, int num, long attr) 828 { 829 struct stic_info *si; 830 struct stic_screen *ss; 831 u_int linewidth, i; 832 uint32_t *pb; 833 834 ss = cookie; 835 si = ss->ss_si; 836 837 if (ss->ss_backing != NULL) { 838 pb = (uint32_t *)(ss->ss_backing + row * si->si_consw); 839 for (i = si->si_consw * num; i > 0; i -= 2) 840 *pb++ = (uint32_t)attr; 841 } 842 if ((ss->ss_flags & SS_ACTIVE) == 0) 843 return; 844 845 row *= si->si_fonth; 846 num *= si->si_fonth; 847 attr = (attr & 0xf0) >> 4; 848 linewidth = (num << 2) - 1; 849 row = (row << 3) + linewidth; 850 851 pb = (*si->si_pbuf_get)(si); 852 853 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET; 854 pb[1] = 0x01ffffff; 855 pb[2] = 0; 856 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY; 857 pb[4] = linewidth; 858 pb[5] = DUPBYTE0(attr); 859 pb[6] = row; 860 pb[7] = (1280 << 19) | row; 861 862 (*si->si_pbuf_post)(si, pb); 863 } 864 865 static void 866 stic_copyrows(void *cookie, int src, int dst, int height) 867 { 868 struct stic_info *si; 869 struct stic_screen *ss; 870 uint32_t *pb, *pbs; 871 u_int num, inc, adj; 872 873 ss = cookie; 874 si = ss->ss_si; 875 876 if (ss->ss_backing != NULL) 877 bcopy(ss->ss_backing + src * si->si_consw, 878 ss->ss_backing + dst * si->si_consw, 879 si->si_consw * sizeof(*ss->ss_backing) * height); 880 if ((ss->ss_flags & SS_ACTIVE) == 0) 881 return; 882 883 /* 884 * We need to do this in reverse if the destination row is below 885 * the source. 886 */ 887 if (dst > src) { 888 src += height; 889 dst += height; 890 inc = -8; 891 adj = -1; 892 } else { 893 inc = 8; 894 adj = 0; 895 } 896 897 src = (src * si->si_fonth + adj) << 3; 898 dst = (dst * si->si_fonth + adj) << 3; 899 height *= si->si_fonth; 900 901 while (height > 0) { 902 num = (height < 255 ? height : 255); 903 height -= num; 904 905 pbs = (*si->si_pbuf_get)(si); 906 pb = pbs; 907 908 pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET; 909 pb[1] = (num << 24) | 0xffffff; 910 pb[2] = 0x0; 911 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN | 912 STAMP_COPYSPAN_ALIGNED; 913 pb[4] = 1; /* linewidth */ 914 915 for (; num != 0; num--, src += inc, dst += inc, pb += 3) { 916 pb[5] = 1280 << 3; 917 pb[6] = src; 918 pb[7] = dst; 919 } 920 921 (*si->si_pbuf_post)(si, pbs); 922 } 923 } 924 925 static void 926 stic_copycols(void *cookie, int row, int src, int dst, int num) 927 { 928 struct stic_info *si; 929 struct stic_screen *ss; 930 u_int height, updword; 931 uint32_t *pb, *pbs; 932 933 ss = cookie; 934 si = ss->ss_si; 935 936 if (ss->ss_backing != NULL) 937 bcopy(ss->ss_backing + row * si->si_consw + src, 938 ss->ss_backing + row * si->si_consw + dst, 939 num * sizeof(*ss->ss_backing)); 940 if ((ss->ss_flags & SS_ACTIVE) == 0) 941 return; 942 943 /* 944 * The stamp reads and writes left -> right only, so we need to 945 * buffer the span if the source and destination regions overlap 946 * and the source is left of the destination. 947 */ 948 updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN; 949 950 if (src < dst && src + num > dst) 951 updword |= STAMP_HALF_BUFF; 952 953 row = (row * si->si_fonth) << 3; 954 num = (num * si->si_fontw) << 3; 955 src = row | ((src * si->si_fontw) << 19); 956 dst = row | ((dst * si->si_fontw) << 19); 957 height = si->si_fonth; 958 959 pbs = (*si->si_pbuf_get)(si); 960 pb = pbs; 961 962 pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET; 963 pb[1] = (height << 24) | 0xffffff; 964 pb[2] = 0x0; 965 pb[3] = updword; 966 pb[4] = 1; /* linewidth */ 967 968 for ( ; height != 0; height--, src += 8, dst += 8, pb += 3) { 969 pb[5] = num; 970 pb[6] = src; 971 pb[7] = dst; 972 } 973 974 (*si->si_pbuf_post)(si, pbs); 975 } 976 977 static void 978 stic_putchar(void *cookie, int r, int c, u_int uc, long attr) 979 { 980 struct wsdisplay_font *font; 981 struct stic_screen *ss; 982 struct stic_info *si; 983 u_int i, bgcolor, fgcolor; 984 u_int *pb, v1, v2, xya; 985 u_short *fr; 986 987 ss = cookie; 988 si = ss->ss_si; 989 990 /* It's cheaper to use erasecols() to blit blanks. */ 991 if (uc == 0) { 992 stic_erasecols(cookie, r, c, 1, attr); 993 return; 994 } 995 996 if (ss->ss_backing != NULL) 997 ss->ss_backing[r * si->si_consw + c] = 998 (u_short)((attr & 0xff) | (uc << 8)); 999 if ((ss->ss_flags & SS_ACTIVE) == 0) 1000 return; 1001 1002 font = si->si_font; 1003 pb = (*si->si_pbuf_get)(si); 1004 1005 /* 1006 * Create a mask from the glyph. Squeeze the foreground color 1007 * through the mask, and then squeeze the background color through 1008 * the inverted mask. We may well read outside the glyph when 1009 * creating the mask, but it's bounded by the hardware so it 1010 * shouldn't matter a great deal... 1011 */ 1012 pb[0] = STAMP_CMD_LINES | STAMP_RGB_FLAT | STAMP_XY_PERPRIMATIVE | 1013 STAMP_LW_PERPRIMATIVE; 1014 pb[1] = font->fontheight > 16 ? 0x04ffffff : 0x02ffffff; 1015 pb[2] = 0x0; 1016 pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY; 1017 1018 r *= font->fontheight; 1019 c *= font->fontwidth; 1020 uc = (uc - font->firstchar) * font->stride * font->fontheight; 1021 fr = (u_short *)((char *)font->data + uc); 1022 bgcolor = DUPBYTE0((attr & 0xf0) >> 4); 1023 fgcolor = DUPBYTE0(attr & 0x0f); 1024 1025 i = ((font->fontheight > 16 ? 16 : font->fontheight) << 2) - 1; 1026 v1 = (c << 19) | ((r << 3) + i); 1027 v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff); 1028 xya = XYMASKADDR(si->si_stampw, si->si_stamphm, c, r, 0, 0); 1029 1030 pb[4] = PACK(fr, 0); 1031 pb[5] = PACK(fr, 2); 1032 pb[6] = PACK(fr, 4); 1033 pb[7] = PACK(fr, 6); 1034 pb[8] = PACK(fr, 8); 1035 pb[9] = PACK(fr, 10); 1036 pb[10] = PACK(fr, 12); 1037 pb[11] = PACK(fr, 14); 1038 pb[12] = xya; 1039 pb[13] = v1; 1040 pb[14] = v2; 1041 pb[15] = i; 1042 pb[16] = fgcolor; 1043 1044 pb[17] = ~pb[4]; 1045 pb[18] = ~pb[5]; 1046 pb[19] = ~pb[6]; 1047 pb[20] = ~pb[7]; 1048 pb[21] = ~pb[8]; 1049 pb[22] = ~pb[9]; 1050 pb[23] = ~pb[10]; 1051 pb[24] = ~pb[11]; 1052 pb[25] = xya; 1053 pb[26] = v1; 1054 pb[27] = v2; 1055 pb[28] = i; 1056 pb[29] = bgcolor; 1057 1058 /* Two more squeezes for the lower part of the character. */ 1059 if (font->fontheight > 16) { 1060 i = ((font->fontheight - 16) << 2) - 1; 1061 r += 16; 1062 v1 = (c << 19) | ((r << 3) + i); 1063 v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff); 1064 1065 pb[30] = PACK(fr, 16); 1066 pb[31] = PACK(fr, 18); 1067 pb[32] = PACK(fr, 20); 1068 pb[33] = PACK(fr, 22); 1069 pb[34] = PACK(fr, 24); 1070 pb[35] = PACK(fr, 26); 1071 pb[36] = PACK(fr, 28); 1072 pb[37] = PACK(fr, 30); 1073 pb[38] = xya; 1074 pb[39] = v1; 1075 pb[40] = v2; 1076 pb[41] = i; 1077 pb[42] = fgcolor; 1078 1079 pb[43] = ~pb[30]; 1080 pb[44] = ~pb[31]; 1081 pb[45] = ~pb[32]; 1082 pb[46] = ~pb[33]; 1083 pb[47] = ~pb[34]; 1084 pb[48] = ~pb[35]; 1085 pb[49] = ~pb[36]; 1086 pb[50] = ~pb[37]; 1087 pb[51] = xya; 1088 pb[52] = v1; 1089 pb[53] = v2; 1090 pb[54] = i; 1091 pb[55] = bgcolor; 1092 } 1093 1094 (*si->si_pbuf_post)(si, pb); 1095 } 1096 1097 static int 1098 stic_mapchar(void *cookie, int c, u_int *cp) 1099 { 1100 struct stic_info *si; 1101 1102 si = ((struct stic_screen *)cookie)->ss_si; 1103 1104 if (c < si->si_font->firstchar || c == ' ') { 1105 *cp = 0; 1106 return (0); 1107 } 1108 1109 if (c - si->si_font->firstchar >= si->si_font->numchars) { 1110 *cp = 0; 1111 return (0); 1112 } 1113 1114 *cp = c; 1115 return (5); 1116 } 1117 1118 static void 1119 stic_cursor(void *cookie, int on, int row, int col) 1120 { 1121 struct stic_screen *ss; 1122 struct stic_info *si; 1123 int s; 1124 1125 ss = cookie; 1126 si = ss->ss_si; 1127 1128 ss->ss_curx = col * si->si_fontw; 1129 ss->ss_cury = row * si->si_fonth; 1130 1131 s = spltty(); 1132 1133 if (on) 1134 ss->ss_flags |= SS_CURENB; 1135 else 1136 ss->ss_flags &= ~SS_CURENB; 1137 1138 if ((ss->ss_flags & SS_ACTIVE) != 0) { 1139 si->si_cursor.cc_pos.x = ss->ss_curx; 1140 si->si_cursor.cc_pos.y = ss->ss_cury; 1141 si->si_flags |= SI_CURENB_CHANGED; 1142 stic_set_hwcurpos(si); 1143 1144 /* 1145 * XXX Since we don't yet receive vblank interrupts from the 1146 * PXG, we must flush immediately. 1147 */ 1148 if (si->si_disptype == WSDISPLAY_TYPE_PXG) 1149 stic_flush(si); 1150 } 1151 1152 splx(s); 1153 } 1154 1155 void 1156 stic_flush(struct stic_info *si) 1157 { 1158 volatile uint32_t *vdac; 1159 int v; 1160 1161 if ((si->si_flags & SI_ALL_CHANGED) == 0) 1162 return; 1163 1164 vdac = si->si_vdac; 1165 v = si->si_flags; 1166 si->si_flags &= ~SI_ALL_CHANGED; 1167 1168 if ((v & SI_CURENB_CHANGED) != 0) { 1169 SELECT(vdac, BT459_IREG_CCR); 1170 if ((si->si_curscreen->ss_flags & SS_CURENB) != 0) 1171 REG(vdac, bt_reg) = 0x00c0c0c0; 1172 else 1173 REG(vdac, bt_reg) = 0x00000000; 1174 tc_wmb(); 1175 } 1176 1177 if ((v & SI_CURCMAP_CHANGED) != 0) { 1178 uint8_t *cp; 1179 1180 cp = si->si_cursor.cc_color; 1181 1182 SELECT(vdac, BT459_IREG_CCOLOR_2); 1183 REG(vdac, bt_reg) = DUPBYTE0(cp[1]); tc_wmb(); 1184 REG(vdac, bt_reg) = DUPBYTE0(cp[3]); tc_wmb(); 1185 REG(vdac, bt_reg) = DUPBYTE0(cp[5]); tc_wmb(); 1186 REG(vdac, bt_reg) = DUPBYTE0(cp[0]); tc_wmb(); 1187 REG(vdac, bt_reg) = DUPBYTE0(cp[2]); tc_wmb(); 1188 REG(vdac, bt_reg) = DUPBYTE0(cp[4]); tc_wmb(); 1189 } 1190 1191 if ((v & SI_CURSHAPE_CHANGED) != 0) { 1192 uint8_t *ip, *mp, img, msk; 1193 uint8_t u; 1194 int bcnt; 1195 1196 ip = (uint8_t *)si->si_cursor.cc_image; 1197 mp = (uint8_t *)si->si_cursor.cc_mask; 1198 1199 bcnt = 0; 1200 SELECT(vdac, BT459_IREG_CRAM_BASE); 1201 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 1202 while (bcnt < CURSOR_MAX_SIZE * 16) { 1203 img = *ip++; 1204 msk = *mp++; 1205 img &= msk; /* cookie off image */ 1206 u = (msk & 0x0f) << 4 | (img & 0x0f); 1207 REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]); 1208 tc_wmb(); 1209 u = (msk & 0xf0) | (img & 0xf0) >> 4; 1210 REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]); 1211 tc_wmb(); 1212 bcnt += 2; 1213 } 1214 } 1215 1216 if ((v & SI_CMAP_CHANGED) != 0) { 1217 struct stic_hwcmap256 *cm; 1218 int index; 1219 1220 cm = &si->si_cmap; 1221 1222 SELECT(vdac, 0); 1223 SELECT(vdac, 0); 1224 for (index = 0; index < CMAP_SIZE; index++) { 1225 REG(vdac, bt_cmap) = DUPBYTE0(cm->r[index]); 1226 tc_wmb(); 1227 REG(vdac, bt_cmap) = DUPBYTE0(cm->g[index]); 1228 tc_wmb(); 1229 REG(vdac, bt_cmap) = DUPBYTE0(cm->b[index]); 1230 tc_wmb(); 1231 } 1232 } 1233 } 1234 1235 static int 1236 stic_get_cmap(struct stic_info *si, struct wsdisplay_cmap *p) 1237 { 1238 u_int index = p->index, count = p->count; 1239 int error; 1240 1241 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 1242 return (EINVAL); 1243 1244 error = copyout(&si->si_cmap.r[index], p->red, count); 1245 if (error) 1246 return error; 1247 error = copyout(&si->si_cmap.g[index], p->green, count); 1248 if (error) 1249 return error; 1250 error = copyout(&si->si_cmap.b[index], p->blue, count); 1251 return error; 1252 } 1253 1254 static int 1255 stic_set_cmap(struct stic_info *si, struct wsdisplay_cmap *p) 1256 { 1257 struct stic_hwcmap256 cmap; 1258 u_int index, count; 1259 int s, error; 1260 1261 index = p->index; 1262 count = p->count; 1263 1264 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 1265 return (EINVAL); 1266 1267 error = copyin(p->red, &cmap.r[index], count); 1268 if (error) 1269 return error; 1270 error = copyin(p->green, &cmap.g[index], count); 1271 if (error) 1272 return error; 1273 error = copyin(p->blue, &cmap.b[index], count); 1274 if (error) 1275 return error; 1276 1277 s = spltty(); 1278 memcpy(&si->si_cmap.r[index], &cmap.r[index], count); 1279 memcpy(&si->si_cmap.g[index], &cmap.g[index], count); 1280 memcpy(&si->si_cmap.b[index], &cmap.b[index], count); 1281 si->si_flags |= SI_CMAP_CHANGED; 1282 splx(s); 1283 1284 /* 1285 * XXX Since we don't yet receive vblank interrupts from the PXG, we 1286 * must flush immediately. 1287 */ 1288 if (si->si_disptype == WSDISPLAY_TYPE_PXG) 1289 stic_flush(si); 1290 1291 return (0); 1292 } 1293 1294 static int 1295 stic_set_cursor(struct stic_info *si, struct wsdisplay_cursor *p) 1296 { 1297 #define cc (&si->si_cursor) 1298 u_int v, index = 0, count = 0, icount = 0; 1299 struct stic_screen *ss; 1300 uint8_t r[2], g[2], b[2], image[512], mask[512]; 1301 int s, error; 1302 1303 v = p->which; 1304 ss = si->si_curscreen; 1305 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) { 1306 index = p->cmap.index; 1307 count = p->cmap.count; 1308 if (index >= 2 || count > 2 - index) 1309 return (EINVAL); 1310 error = copyin(p->cmap.red, &r[index], count); 1311 if (error) 1312 return error; 1313 error = copyin(p->cmap.green, &g[index], count); 1314 if (error) 1315 return error; 1316 error = copyin(p->cmap.blue, &b[index], count); 1317 if (error) 1318 return error; 1319 } 1320 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) { 1321 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 1322 return (EINVAL); 1323 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 1324 error = copyin(p->image, image, icount); 1325 if (error) 1326 return error; 1327 error = copyin(p->mask, mask, icount); 1328 if (error) 1329 return error; 1330 } 1331 if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) != 0) { 1332 if (v & WSDISPLAY_CURSOR_DOCUR) 1333 cc->cc_hot = p->hot; 1334 if (v & WSDISPLAY_CURSOR_DOPOS) 1335 stic_set_curpos(si, &p->pos); 1336 } 1337 1338 s = spltty(); 1339 if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) { 1340 if (p->enable) 1341 ss->ss_flags |= SS_CURENB; 1342 else 1343 ss->ss_flags &= ~SS_CURENB; 1344 si->si_flags |= SI_CURENB_CHANGED; 1345 } 1346 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) { 1347 memcpy(&cc->cc_color[index], &r[index], count); 1348 memcpy(&cc->cc_color[index + 2], &g[index], count); 1349 memcpy(&cc->cc_color[index + 4], &b[index], count); 1350 si->si_flags |= SI_CURCMAP_CHANGED; 1351 } 1352 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) { 1353 memset(cc->cc_image, 0, sizeof cc->cc_image); 1354 memcpy(cc->cc_image, image, icount); 1355 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 1356 memcpy(cc->cc_mask, mask, icount); 1357 si->si_flags |= SI_CURSHAPE_CHANGED; 1358 } 1359 splx(s); 1360 1361 /* 1362 * XXX Since we don't yet receive vblank interrupts from the PXG, we 1363 * must flush immediately. 1364 */ 1365 if (si->si_disptype == WSDISPLAY_TYPE_PXG) 1366 stic_flush(si); 1367 1368 return (0); 1369 #undef cc 1370 } 1371 1372 static int 1373 stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p) 1374 { 1375 1376 /* XXX */ 1377 return (EPASSTHROUGH); 1378 } 1379 1380 static void 1381 stic_set_curpos(struct stic_info *si, struct wsdisplay_curpos *curpos) 1382 { 1383 int x, y; 1384 1385 x = curpos->x; 1386 y = curpos->y; 1387 1388 if (y < 0) 1389 y = 0; 1390 else if (y > 1023) 1391 y = 1023; 1392 if (x < 0) 1393 x = 0; 1394 else if (x > 1279) 1395 x = 1279; 1396 1397 si->si_cursor.cc_pos.x = x; 1398 si->si_cursor.cc_pos.y = y; 1399 stic_set_hwcurpos(si); 1400 } 1401 1402 static void 1403 stic_set_hwcurpos(struct stic_info *si) 1404 { 1405 volatile uint32_t *vdac; 1406 int x, y, s; 1407 1408 vdac = si->si_vdac; 1409 1410 x = si->si_cursor.cc_pos.x - si->si_cursor.cc_hot.x; 1411 y = si->si_cursor.cc_pos.y - si->si_cursor.cc_hot.y; 1412 x += STIC_MAGIC_X; 1413 y += STIC_MAGIC_Y; 1414 1415 s = spltty(); 1416 SELECT(vdac, BT459_IREG_CURSOR_X_LOW); 1417 REG(vdac, bt_reg) = DUPBYTE0(x); tc_wmb(); 1418 REG(vdac, bt_reg) = DUPBYTE1(x); tc_wmb(); 1419 REG(vdac, bt_reg) = DUPBYTE0(y); tc_wmb(); 1420 REG(vdac, bt_reg) = DUPBYTE1(y); tc_wmb(); 1421 splx(s); 1422 } 1423 1424 /* 1425 * STIC control inteface. We have a separate device for mapping the board, 1426 * because access to the DMA engine means that it's possible to circumvent 1427 * the securelevel mechanism. 1428 */ 1429 static int 1430 sticopen(dev_t dev, int flag, int mode, struct lwp *l) 1431 { 1432 struct stic_info *si; 1433 int s, error; 1434 1435 error = kauth_authorize_device_passthru(l->l_cred, dev, 1436 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, NULL); 1437 if (error) 1438 return (error); 1439 if (minor(dev) >= STIC_MAXDV) 1440 return (ENXIO); 1441 if ((si = stic_info[minor(dev)]) == NULL) 1442 return (ENXIO); 1443 1444 s = spltty(); 1445 if ((si->si_flags & SI_DVOPEN) != 0) { 1446 splx(s); 1447 return (EBUSY); 1448 } 1449 si->si_flags |= SI_DVOPEN; 1450 splx(s); 1451 1452 return (0); 1453 } 1454 1455 static int 1456 sticclose(dev_t dev, int flag, int mode, struct lwp *l) 1457 { 1458 struct stic_info *si; 1459 int s; 1460 1461 si = stic_info[minor(dev)]; 1462 s = spltty(); 1463 si->si_flags &= ~SI_DVOPEN; 1464 splx(s); 1465 1466 return (0); 1467 } 1468 1469 static paddr_t 1470 sticmmap(dev_t dev, off_t offset, int prot) 1471 { 1472 struct stic_info *si; 1473 struct stic_xmap *sxm; 1474 paddr_t pa; 1475 1476 si = stic_info[minor(dev)]; 1477 sxm = NULL; 1478 1479 if (si->si_dispmode != WSDISPLAYIO_MODE_MAPPED) 1480 return (-1L); 1481 1482 if (offset < 0) 1483 return ((paddr_t)-1L); 1484 1485 if (offset < sizeof(sxm->sxm_stic)) { 1486 pa = STIC_KSEG_TO_PHYS(si->si_stic); 1487 return (machine_btop(pa + offset)); 1488 } 1489 offset -= sizeof(sxm->sxm_stic); 1490 1491 if (offset < sizeof(sxm->sxm_poll)) { 1492 pa = STIC_KSEG_TO_PHYS(si->si_slotbase); 1493 return (machine_btop(pa + offset)); 1494 } 1495 offset -= sizeof(sxm->sxm_poll); 1496 1497 if (offset < si->si_buf_size) 1498 return (machine_btop(si->si_buf_phys + offset)); 1499 1500 return ((paddr_t)-1L); 1501 } 1502