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