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