1/* $NetBSD: stic.c,v 1.59 2022/07/20 15:45:28 thorpej 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.59 2022/07/20 15:45:28 thorpej 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 124static int sticioctl(void *, void *, u_long, void *, int, struct lwp *); 125static int stic_alloc_screen(void *, const struct wsscreen_descr *, 126 void **, int *, int *, long *); 127static void stic_free_screen(void *, void *); 128static int stic_show_screen(void *, void *, int, 129 void (*)(void *, int, int), void *); 130 131static void stic_do_switch(void *); 132static void stic_setup_backing(struct stic_info *, struct stic_screen *); 133static void stic_setup_vdac(struct stic_info *); 134static void stic_clear_screen(struct stic_info *); 135 136static int stic_get_cmap(struct stic_info *, struct wsdisplay_cmap *); 137static int stic_set_cmap(struct stic_info *, struct wsdisplay_cmap *); 138static int stic_set_cursor(struct stic_info *, struct wsdisplay_cursor *); 139static int stic_get_cursor(struct stic_info *, struct wsdisplay_cursor *); 140static void stic_set_curpos(struct stic_info *, struct wsdisplay_curpos *); 141static void stic_set_hwcurpos(struct stic_info *); 142 143static void stic_cursor(void *, int, int, int); 144static void stic_copycols(void *, int, int, int, int); 145static void stic_copyrows(void *, int, int, int); 146static void stic_erasecols(void *, int, int, int, long); 147static void stic_eraserows(void *, int, int, long); 148static int stic_mapchar(void *, int, u_int *); 149static void stic_putchar(void *, int, int, u_int, long); 150static int stic_allocattr(void *, int, int, int, long *); 151 152static dev_type_open(sticopen); 153static dev_type_close(sticclose); 154static dev_type_mmap(sticmmap); 155 156const 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. */ 172static 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 */ 199static 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 234static 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 243static 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 254static struct wsscreen_descr stic_stdscreen = { 255 "std", 256 0, 0, 257 &stic_emulops, 258 0, 0, 259 WSSCREEN_WSCOLORS | WSSCREEN_HILIT 260}; 261 262static const struct wsscreen_descr *_stic_scrlist[] = { 263 &stic_stdscreen, 264}; 265 266static const struct wsscreen_list stic_screenlist = { 267 sizeof(_stic_scrlist) / sizeof(struct wsscreen_descr *), _stic_scrlist 268}; 269 270struct stic_info stic_consinfo; 271static struct stic_screen stic_consscr; 272static struct stic_info *stic_info[STIC_MAXDV]; 273static int stic_unit; 274 275void 276stic_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_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 348void 349stic_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_syncbus(); 361 DELAY(2000); /* wait 2ms for STIC to respond. */ 362 sr->sr_sticsr = 0x00000000; /* Hit the STIC's csr again... */ 363 tc_wmb(); 364 sr->sr_buscsr = 0xffffffff; /* and bash its bus-access csr. */ 365 tc_syncbus(); /* Blam! */ 366 DELAY(20000); /* wait until the stic recovers... */ 367 368 modtype = sr->sr_modcl; 369 xconfig = (modtype & 0x800) >> 11; 370 yconfig = (modtype & 0x600) >> 9; 371 config = (yconfig << 1) | xconfig; 372 si->si_stampw = (xconfig ? 5 : 4); 373 si->si_stamph = (1 << yconfig); 374 si->si_stamphm = si->si_stamph - 1; 375#ifdef notyet 376 si->si_option = (char)((modtype >> 12) & 3); 377#endif 378 379 /* First PixelStamp */ 380 si->si_stamp[0x000b0] = config; 381 si->si_stamp[0x000b4] = 0x0; 382 383 /* Second PixelStamp */ 384 if (yconfig > 0) { 385 si->si_stamp[0x100b0] = config | 8; 386 si->si_stamp[0x100b4] = 0; 387 } 388 389 /* 390 * Initialize STIC video registers. Enable error and vertical 391 * retrace interrupts. Set the packet done flag so the Xserver will 392 * not time-out on the first packet submitted. 393 */ 394 sr->sr_vblank = (1024 << 16) | 1063; 395 sr->sr_vsync = (1027 << 16) | 1030; 396 sr->sr_hblank = (255 << 16) | 340; 397 sr->sr_hsync2 = 245; 398 sr->sr_hsync = (261 << 16) | 293; 399 sr->sr_ipdvint = 400 STIC_INT_WE | STIC_INT_P | STIC_INT_E_EN | STIC_INT_V_EN; 401 sr->sr_sticsr = 8; 402 tc_syncbus(); 403} 404 405void 406stic_attach(device_t self, struct stic_info *si, int console) 407{ 408 struct wsemuldisplaydev_attach_args waa; 409 410 if (stic_unit < STIC_MAXDV) { 411 stic_info[stic_unit] = si; 412 si->si_unit = stic_unit++; 413 } else 414 si->si_unit = -1; 415 416 callout_init(&si->si_switch_callout, 0); 417 418 /* 419 * Allocate backing for the console. We could trawl back through 420 * msgbuf and fill the backing, but it's not worth the hassle. 421 * We could also grab backing using pmap_steal_memory() early on, 422 * but that's a little ugly. 423 */ 424 if (console) 425 stic_setup_backing(si, &stic_consscr); 426 427 waa.console = console; 428 waa.scrdata = &stic_screenlist; 429 waa.accessops = &stic_accessops; 430 waa.accesscookie = si; 431 432 config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE); 433} 434 435void 436stic_cnattach(struct stic_info *si) 437{ 438 struct stic_screen *ss; 439 long defattr; 440 441 ss = &stic_consscr; 442 si->si_curscreen = ss; 443 ss->ss_flags = SS_ALLOCED | SS_ACTIVE | SS_CURENB; 444 ss->ss_si = si; 445 446 si->si_flags |= SI_CURENB_CHANGED; 447 stic_flush(si); 448 449 stic_allocattr(ss, 0, 0, 0, &defattr); 450 stic_eraserows(ss, 0, si->si_consh, 0); 451 wsdisplay_cnattach(&stic_stdscreen, ss, 0, 0, defattr); 452} 453 454static void 455stic_setup_vdac(struct stic_info *si) 456{ 457 uint8_t *ip, *mp; 458 int r, c, o, b, i, s; 459 460 s = spltty(); 461 462 ip = (uint8_t *)si->si_cursor.cc_image; 463 mp = (uint8_t *)si->si_cursor.cc_mask; 464 memset(ip, 0, sizeof(si->si_cursor.cc_image)); 465 memset(mp, 0, sizeof(si->si_cursor.cc_mask)); 466 467 for (r = 0; r < si->si_fonth; r++) { 468 for (c = r & 1; c < si->si_fontw; c += 2) { 469 o = c >> 3; 470 b = 1 << (c & 7); 471 ip[o] |= b; 472 mp[o] |= b; 473 } 474 475 ip += 8; 476 mp += 8; 477 } 478 479 si->si_cursor.cc_size.x = 64; 480 si->si_cursor.cc_size.y = si->si_fonth; 481 si->si_cursor.cc_hot.x = 0; 482 si->si_cursor.cc_hot.y = 0; 483 484 si->si_cursor.cc_color[0] = 0xff; 485 si->si_cursor.cc_color[2] = 0xff; 486 si->si_cursor.cc_color[4] = 0xff; 487 si->si_cursor.cc_color[1] = 0x00; 488 si->si_cursor.cc_color[3] = 0x00; 489 si->si_cursor.cc_color[5] = 0x00; 490 491 memset(&si->si_cmap, 0, sizeof(si->si_cmap)); 492 for (i = 0; i < 16; i++) { 493 si->si_cmap.r[i] = stic_cmap[i*3 + 0]; 494 si->si_cmap.g[i] = stic_cmap[i*3 + 1]; 495 si->si_cmap.b[i] = stic_cmap[i*3 + 2]; 496 } 497 498 si->si_flags |= SI_CMAP_CHANGED | SI_CURSHAPE_CHANGED | 499 SI_CURCMAP_CHANGED; 500 501 splx(s); 502} 503 504static void 505stic_clear_screen(struct stic_info *si) 506{ 507 uint32_t *pb; 508 int i; 509 510 /* 511 * Do this twice, since the first packet after a reset may be 512 * silently ignored. 513 */ 514 for (i = 0; i < 2; i++) { 515 pb = (*si->si_pbuf_get)(si); 516 517 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET; 518 pb[1] = 0x01ffffff; 519 pb[2] = 0; 520 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY; 521 pb[4] = (1024 << 2) - 1; 522 pb[5] = 0; 523 pb[6] = 0; 524 pb[7] = (1280 << 19) | ((1024 << 3) + pb[4]); 525 526 (*si->si_pbuf_post)(si, pb); 527 } 528} 529 530static int 531sticioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 532{ 533 struct stic_info *si; 534 int s; 535 536 si = v; 537 538 switch (cmd) { 539 case WSDISPLAYIO_GTYPE: 540 *(u_int *)data = si->si_disptype; 541 return (0); 542 543 case WSDISPLAYIO_GINFO: 544#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 545 wsd_fbip->height = 1024; 546 wsd_fbip->width = 1280; 547 wsd_fbip->depth = si->si_depth == 8 ? 8 : 32; 548 wsd_fbip->cmsize = CMAP_SIZE; 549#undef fbt 550 return (0); 551 552 case WSDISPLAYIO_GETCMAP: 553 return (stic_get_cmap(si, (struct wsdisplay_cmap *)data)); 554 555 case WSDISPLAYIO_PUTCMAP: 556 return (stic_set_cmap(si, (struct wsdisplay_cmap *)data)); 557 558 case WSDISPLAYIO_SVIDEO: 559#if 0 /* XXX later */ 560 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 561 if ((si->si_blanked == 0) ^ turnoff) 562 si->si_blanked = turnoff; 563#endif 564 return (0); 565 566 case WSDISPLAYIO_GVIDEO: 567#if 0 /* XXX later */ 568 *(u_int *)data = si->si_blanked ? 569 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 570#endif 571 return (0); 572 573 case WSDISPLAYIO_GCURPOS: 574 *(struct wsdisplay_curpos *)data = si->si_cursor.cc_pos; 575 return (0); 576 577 case WSDISPLAYIO_SCURPOS: 578 stic_set_curpos(si, (struct wsdisplay_curpos *)data); 579 return (0); 580 581 case WSDISPLAYIO_GCURMAX: 582 ((struct wsdisplay_curpos *)data)->x = 583 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 584 return (0); 585 586 case WSDISPLAYIO_GCURSOR: 587 return (stic_get_cursor(si, (struct wsdisplay_cursor *)data)); 588 589 case WSDISPLAYIO_SCURSOR: 590 return (stic_set_cursor(si, (struct wsdisplay_cursor *)data)); 591 592 case WSDISPLAYIO_SMODE: 593 si->si_dispmode = *(int *)data; 594 if (si->si_dispmode == WSDISPLAYIO_MODE_EMUL) { 595 (*si->si_ioctl)(si, STICIO_STOPQ, NULL, flag, l); 596 stic_setup_vdac(si); 597 s = spltty(); 598 stic_flush(si); 599 splx(s); 600 stic_clear_screen(si); 601 stic_do_switch(si->si_curscreen); 602 } 603 return (0); 604 605 case STICIO_RESET: 606 stic_reset(si); 607 return (0); 608 } 609 610 if (si->si_ioctl != NULL) 611 return ((*si->si_ioctl)(si, cmd, data, flag, l)); 612 613 return (EPASSTHROUGH); 614} 615 616static void 617stic_setup_backing(struct stic_info *si, struct stic_screen *ss) 618{ 619 int size; 620 621 size = si->si_consw * si->si_consh * sizeof(*ss->ss_backing); 622 ss->ss_backing = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO); 623} 624 625static int 626stic_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 627 int *curxp, int *curyp, long *attrp) 628{ 629 struct stic_info *si; 630 struct stic_screen *ss; 631 632 si = (struct stic_info *)v; 633 634 if ((stic_consscr.ss_flags & SS_ALLOCED) == 0) 635 ss = &stic_consscr; 636 else { 637 ss = malloc(sizeof(*ss), M_DEVBUF, M_WAITOK|M_ZERO); 638 } 639 stic_setup_backing(si, ss); 640 641 ss->ss_si = si; 642 ss->ss_flags = SS_ALLOCED | SS_CURENB; 643 644 *cookiep = ss; 645 *curxp = 0; 646 *curyp = 0; 647 648 stic_allocattr(ss, 0, 0, 0, attrp); 649 return (0); 650} 651 652static void 653stic_free_screen(void *v, void *cookie) 654{ 655 struct stic_screen *ss; 656 657 ss = cookie; 658 659#ifdef DIAGNOSTIC 660 if (ss == &stic_consscr) 661 panic("stic_free_screen: console"); 662 if (ss == ((struct stic_info *)v)->si_curscreen) 663 panic("stic_free_screen: freeing current screen"); 664#endif 665 666 free(ss->ss_backing, M_DEVBUF); 667 free(ss, M_DEVBUF); 668} 669 670static int 671stic_show_screen(void *v, void *cookie, int waitok, 672 void (*cb)(void *, int, int), void *cbarg) 673{ 674 struct stic_info *si; 675 676 si = (struct stic_info *)v; 677 if (si->si_switchcbarg != NULL) 678 return (EAGAIN); 679 si->si_switchcb = cb; 680 si->si_switchcbarg = cbarg; 681 682 if (cb != NULL) { 683 callout_reset(&si->si_switch_callout, 0, stic_do_switch, 684 cookie); 685 return (EAGAIN); 686 } 687 688 stic_do_switch(cookie); 689 return (0); 690} 691 692static void 693stic_do_switch(void *cookie) 694{ 695 struct stic_screen *ss; 696 struct stic_info *si; 697 u_int r, c, nr, nc; 698 uint16_t *p, *sp; 699 700 ss = cookie; 701 si = ss->ss_si; 702 703#ifdef DIAGNOSTIC 704 if (ss->ss_backing == NULL) 705 panic("stic_do_switch: screen not backed"); 706#endif 707 708 /* Swap in the new screen, and temporarily disable its backing. */ 709 if (si->si_curscreen != NULL) 710 si->si_curscreen->ss_flags ^= SS_ACTIVE; 711 si->si_curscreen = ss; 712 ss->ss_flags |= SS_ACTIVE; 713 sp = ss->ss_backing; 714 ss->ss_backing = NULL; 715 716 /* 717 * We assume that most of the screen is blank and blast it with 718 * eraserows(), because eraserows() is cheap. 719 */ 720 nr = si->si_consh; 721 stic_eraserows(ss, 0, nr, 0); 722 723 nc = si->si_consw; 724 p = sp; 725 for (r = 0; r < nr; r++) 726 for (c = 0; c < nc; c += 2, p += 2) { 727 if ((p[0] & 0xfff0) != 0) 728 stic_putchar(ss, r, c, p[0] >> 8, 729 p[0] & 0x00ff); 730 if ((p[1] & 0xfff0) != 0) 731 stic_putchar(ss, r, c + 1, p[1] >> 8, 732 p[1] & 0x00ff); 733 } 734 735 /* 736 * Re-enable the screen's backing, and move the cursor to the 737 * correct spot. 738 */ 739 ss->ss_backing = sp; 740 si->si_cursor.cc_pos.x = ss->ss_curx; 741 si->si_cursor.cc_pos.y = ss->ss_cury; 742 stic_set_hwcurpos(si); 743 si->si_flags |= SI_CURENB_CHANGED; 744 745 /* 746 * XXX Since we don't yet receive vblank interrupts from the 747 * PXG, we must flush immediately. 748 */ 749 if (si->si_disptype == WSDISPLAY_TYPE_PXG) 750 stic_flush(si); 751 752 /* Tell wscons that we're done. */ 753 if (si->si_switchcbarg != NULL) { 754 cookie = si->si_switchcbarg; 755 si->si_switchcbarg = NULL; 756 (*si->si_switchcb)(cookie, 0, 0); 757 } 758} 759 760static int 761stic_allocattr(void *cookie, int fg, int bg, int flags, long *attr) 762{ 763 long tmp; 764 765 if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0) 766 return (EINVAL); 767 768 if ((flags & WSATTR_WSCOLORS) == 0) { 769 fg = 7; 770 bg = 0; 771 } 772 773 if ((flags & WSATTR_HILIT) != 0) 774 fg += 8; 775 776 tmp = fg | (bg << 4); 777 *attr = tmp | (tmp << 16); 778 return (0); 779} 780 781static void 782stic_erasecols(void *cookie, int row, int col, int num, long attr) 783{ 784 struct stic_info *si; 785 struct stic_screen *ss; 786 uint32_t *pb; 787 u_int i, linewidth; 788 uint16_t *p; 789 790 ss = cookie; 791 si = ss->ss_si; 792 793 if (ss->ss_backing != NULL) { 794 p = ss->ss_backing + row * si->si_consw + col; 795 for (i = num; i != 0; i--) 796 *p++ = (uint16_t)attr; 797 } 798 if ((ss->ss_flags & SS_ACTIVE) == 0) 799 return; 800 801 col = (col * si->si_fontw) << 19; 802 num = (num * si->si_fontw) << 19; 803 row = row * si->si_fonth; 804 attr = (attr & 0xf0) >> 4; 805 linewidth = (si->si_fonth << 2) - 1; 806 row = (row << 3) + linewidth; 807 808 pb = (*si->si_pbuf_get)(si); 809 810 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET; 811 pb[1] = 0x01ffffff; 812 pb[2] = 0; 813 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY; 814 pb[4] = linewidth; 815 pb[5] = DUPBYTE0(attr); 816 pb[6] = col | row; 817 pb[7] = (col + num) | row; 818 819 (*si->si_pbuf_post)(si, pb); 820} 821 822static void 823stic_eraserows(void *cookie, int row, int num, long attr) 824{ 825 struct stic_info *si; 826 struct stic_screen *ss; 827 u_int linewidth, i; 828 uint32_t *pb; 829 830 ss = cookie; 831 si = ss->ss_si; 832 833 if (ss->ss_backing != NULL) { 834 pb = (uint32_t *)(ss->ss_backing + row * si->si_consw); 835 for (i = si->si_consw * num; i > 0; i -= 2) 836 *pb++ = (uint32_t)attr; 837 } 838 if ((ss->ss_flags & SS_ACTIVE) == 0) 839 return; 840 841 row *= si->si_fonth; 842 num *= si->si_fonth; 843 attr = (attr & 0xf0) >> 4; 844 linewidth = (num << 2) - 1; 845 row = (row << 3) + linewidth; 846 847 pb = (*si->si_pbuf_get)(si); 848 849 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET; 850 pb[1] = 0x01ffffff; 851 pb[2] = 0; 852 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY; 853 pb[4] = linewidth; 854 pb[5] = DUPBYTE0(attr); 855 pb[6] = row; 856 pb[7] = (1280 << 19) | row; 857 858 (*si->si_pbuf_post)(si, pb); 859} 860 861static void 862stic_copyrows(void *cookie, int src, int dst, int height) 863{ 864 struct stic_info *si; 865 struct stic_screen *ss; 866 uint32_t *pb, *pbs; 867 u_int num, inc, adj; 868 869 ss = cookie; 870 si = ss->ss_si; 871 872 if (ss->ss_backing != NULL) 873 bcopy(ss->ss_backing + src * si->si_consw, 874 ss->ss_backing + dst * si->si_consw, 875 si->si_consw * sizeof(*ss->ss_backing) * height); 876 if ((ss->ss_flags & SS_ACTIVE) == 0) 877 return; 878 879 /* 880 * We need to do this in reverse if the destination row is below 881 * the source. 882 */ 883 if (dst > src) { 884 src += height; 885 dst += height; 886 inc = -8; 887 adj = -1; 888 } else { 889 inc = 8; 890 adj = 0; 891 } 892 893 src = (src * si->si_fonth + adj) << 3; 894 dst = (dst * si->si_fonth + adj) << 3; 895 height *= si->si_fonth; 896 897 while (height > 0) { 898 num = (height < 255 ? height : 255); 899 height -= num; 900 901 pbs = (*si->si_pbuf_get)(si); 902 pb = pbs; 903 904 pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET; 905 pb[1] = (num << 24) | 0xffffff; 906 pb[2] = 0x0; 907 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN | 908 STAMP_COPYSPAN_ALIGNED; 909 pb[4] = 1; /* linewidth */ 910 911 for (; num != 0; num--, src += inc, dst += inc, pb += 3) { 912 pb[5] = 1280 << 3; 913 pb[6] = src; 914 pb[7] = dst; 915 } 916 917 (*si->si_pbuf_post)(si, pbs); 918 } 919} 920 921static void 922stic_copycols(void *cookie, int row, int src, int dst, int num) 923{ 924 struct stic_info *si; 925 struct stic_screen *ss; 926 u_int height, updword; 927 uint32_t *pb, *pbs; 928 929 ss = cookie; 930 si = ss->ss_si; 931 932 if (ss->ss_backing != NULL) 933 bcopy(ss->ss_backing + row * si->si_consw + src, 934 ss->ss_backing + row * si->si_consw + dst, 935 num * sizeof(*ss->ss_backing)); 936 if ((ss->ss_flags & SS_ACTIVE) == 0) 937 return; 938 939 /* 940 * The stamp reads and writes left -> right only, so we need to 941 * buffer the span if the source and destination regions overlap 942 * and the source is left of the destination. 943 */ 944 updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN; 945 946 if (src < dst && src + num > dst) 947 updword |= STAMP_HALF_BUFF; 948 949 row = (row * si->si_fonth) << 3; 950 num = (num * si->si_fontw) << 3; 951 src = row | ((src * si->si_fontw) << 19); 952 dst = row | ((dst * si->si_fontw) << 19); 953 height = si->si_fonth; 954 955 pbs = (*si->si_pbuf_get)(si); 956 pb = pbs; 957 958 pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET; 959 pb[1] = (height << 24) | 0xffffff; 960 pb[2] = 0x0; 961 pb[3] = updword; 962 pb[4] = 1; /* linewidth */ 963 964 for ( ; height != 0; height--, src += 8, dst += 8, pb += 3) { 965 pb[5] = num; 966 pb[6] = src; 967 pb[7] = dst; 968 } 969 970 (*si->si_pbuf_post)(si, pbs); 971} 972 973static void 974stic_putchar(void *cookie, int r, int c, u_int uc, long attr) 975{ 976 struct wsdisplay_font *font; 977 struct stic_screen *ss; 978 struct stic_info *si; 979 u_int i, bgcolor, fgcolor; 980 u_int *pb, v1, v2, xya; 981 u_short *fr; 982 983 ss = cookie; 984 si = ss->ss_si; 985 986 /* It's cheaper to use erasecols() to blit blanks. */ 987 if (uc == 0) { 988 stic_erasecols(cookie, r, c, 1, attr); 989 return; 990 } 991 992 if (ss->ss_backing != NULL) 993 ss->ss_backing[r * si->si_consw + c] = 994 (u_short)((attr & 0xff) | (uc << 8)); 995 if ((ss->ss_flags & SS_ACTIVE) == 0) 996 return; 997 998 font = si->si_font; 999 pb = (*si->si_pbuf_get)(si); 1000 1001 /* 1002 * Create a mask from the glyph. Squeeze the foreground color 1003 * through the mask, and then squeeze the background color through 1004 * the inverted mask. We may well read outside the glyph when 1005 * creating the mask, but it's bounded by the hardware so it 1006 * shouldn't matter a great deal... 1007 */ 1008 pb[0] = STAMP_CMD_LINES | STAMP_RGB_FLAT | STAMP_XY_PERPRIMATIVE | 1009 STAMP_LW_PERPRIMATIVE; 1010 pb[1] = font->fontheight > 16 ? 0x04ffffff : 0x02ffffff; 1011 pb[2] = 0x0; 1012 pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY; 1013 1014 r *= font->fontheight; 1015 c *= font->fontwidth; 1016 uc = (uc - font->firstchar) * font->stride * font->fontheight; 1017 fr = (u_short *)((char *)font->data + uc); 1018 bgcolor = DUPBYTE0((attr & 0xf0) >> 4); 1019 fgcolor = DUPBYTE0(attr & 0x0f); 1020 1021 i = ((font->fontheight > 16 ? 16 : font->fontheight) << 2) - 1; 1022 v1 = (c << 19) | ((r << 3) + i); 1023 v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff); 1024 xya = XYMASKADDR(si->si_stampw, si->si_stamphm, c, r, 0, 0); 1025 1026 pb[4] = PACK(fr, 0); 1027 pb[5] = PACK(fr, 2); 1028 pb[6] = PACK(fr, 4); 1029 pb[7] = PACK(fr, 6); 1030 pb[8] = PACK(fr, 8); 1031 pb[9] = PACK(fr, 10); 1032 pb[10] = PACK(fr, 12); 1033 pb[11] = PACK(fr, 14); 1034 pb[12] = xya; 1035 pb[13] = v1; 1036 pb[14] = v2; 1037 pb[15] = i; 1038 pb[16] = fgcolor; 1039 1040 pb[17] = ~pb[4]; 1041 pb[18] = ~pb[5]; 1042 pb[19] = ~pb[6]; 1043 pb[20] = ~pb[7]; 1044 pb[21] = ~pb[8]; 1045 pb[22] = ~pb[9]; 1046 pb[23] = ~pb[10]; 1047 pb[24] = ~pb[11]; 1048 pb[25] = xya; 1049 pb[26] = v1; 1050 pb[27] = v2; 1051 pb[28] = i; 1052 pb[29] = bgcolor; 1053 1054 /* Two more squeezes for the lower part of the character. */ 1055 if (font->fontheight > 16) { 1056 i = ((font->fontheight - 16) << 2) - 1; 1057 r += 16; 1058 v1 = (c << 19) | ((r << 3) + i); 1059 v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff); 1060 1061 pb[30] = PACK(fr, 16); 1062 pb[31] = PACK(fr, 18); 1063 pb[32] = PACK(fr, 20); 1064 pb[33] = PACK(fr, 22); 1065 pb[34] = PACK(fr, 24); 1066 pb[35] = PACK(fr, 26); 1067 pb[36] = PACK(fr, 28); 1068 pb[37] = PACK(fr, 30); 1069 pb[38] = xya; 1070 pb[39] = v1; 1071 pb[40] = v2; 1072 pb[41] = i; 1073 pb[42] = fgcolor; 1074 1075 pb[43] = ~pb[30]; 1076 pb[44] = ~pb[31]; 1077 pb[45] = ~pb[32]; 1078 pb[46] = ~pb[33]; 1079 pb[47] = ~pb[34]; 1080 pb[48] = ~pb[35]; 1081 pb[49] = ~pb[36]; 1082 pb[50] = ~pb[37]; 1083 pb[51] = xya; 1084 pb[52] = v1; 1085 pb[53] = v2; 1086 pb[54] = i; 1087 pb[55] = bgcolor; 1088 } 1089 1090 (*si->si_pbuf_post)(si, pb); 1091} 1092 1093static int 1094stic_mapchar(void *cookie, int c, u_int *cp) 1095{ 1096 struct stic_info *si; 1097 1098 si = ((struct stic_screen *)cookie)->ss_si; 1099 1100 if (c < si->si_font->firstchar || c == ' ') { 1101 *cp = 0; 1102 return (0); 1103 } 1104 1105 if (c - si->si_font->firstchar >= si->si_font->numchars) { 1106 *cp = 0; 1107 return (0); 1108 } 1109 1110 *cp = c; 1111 return (5); 1112} 1113 1114static void 1115stic_cursor(void *cookie, int on, int row, int col) 1116{ 1117 struct stic_screen *ss; 1118 struct stic_info *si; 1119 int s; 1120 1121 ss = cookie; 1122 si = ss->ss_si; 1123 1124 ss->ss_curx = col * si->si_fontw; 1125 ss->ss_cury = row * si->si_fonth; 1126 1127 s = spltty(); 1128 1129 if (on) 1130 ss->ss_flags |= SS_CURENB; 1131 else 1132 ss->ss_flags &= ~SS_CURENB; 1133 1134 if ((ss->ss_flags & SS_ACTIVE) != 0) { 1135 si->si_cursor.cc_pos.x = ss->ss_curx; 1136 si->si_cursor.cc_pos.y = ss->ss_cury; 1137 si->si_flags |= SI_CURENB_CHANGED; 1138 stic_set_hwcurpos(si); 1139 1140 /* 1141 * XXX Since we don't yet receive vblank interrupts from the 1142 * PXG, we must flush immediately. 1143 */ 1144 if (si->si_disptype == WSDISPLAY_TYPE_PXG) 1145 stic_flush(si); 1146 } 1147 1148 splx(s); 1149} 1150 1151void 1152stic_flush(struct stic_info *si) 1153{ 1154 volatile uint32_t *vdac; 1155 int v; 1156 1157 if ((si->si_flags & SI_ALL_CHANGED) == 0) 1158 return; 1159 1160 vdac = si->si_vdac; 1161 v = si->si_flags; 1162 si->si_flags &= ~SI_ALL_CHANGED; 1163 1164 if ((v & SI_CURENB_CHANGED) != 0) { 1165 SELECT(vdac, BT459_IREG_CCR); 1166 if ((si->si_curscreen->ss_flags & SS_CURENB) != 0) 1167 REG(vdac, bt_reg) = 0x00c0c0c0; 1168 else 1169 REG(vdac, bt_reg) = 0x00000000; 1170 tc_wmb(); 1171 } 1172 1173 if ((v & SI_CURCMAP_CHANGED) != 0) { 1174 uint8_t *cp; 1175 1176 cp = si->si_cursor.cc_color; 1177 1178 SELECT(vdac, BT459_IREG_CCOLOR_2); 1179 REG(vdac, bt_reg) = DUPBYTE0(cp[1]); tc_wmb(); 1180 REG(vdac, bt_reg) = DUPBYTE0(cp[3]); tc_wmb(); 1181 REG(vdac, bt_reg) = DUPBYTE0(cp[5]); tc_wmb(); 1182 REG(vdac, bt_reg) = DUPBYTE0(cp[0]); tc_wmb(); 1183 REG(vdac, bt_reg) = DUPBYTE0(cp[2]); tc_wmb(); 1184 REG(vdac, bt_reg) = DUPBYTE0(cp[4]); tc_wmb(); 1185 } 1186 1187 if ((v & SI_CURSHAPE_CHANGED) != 0) { 1188 uint8_t *ip, *mp, img, msk; 1189 uint8_t u; 1190 int bcnt; 1191 1192 ip = (uint8_t *)si->si_cursor.cc_image; 1193 mp = (uint8_t *)si->si_cursor.cc_mask; 1194 1195 bcnt = 0; 1196 SELECT(vdac, BT459_IREG_CRAM_BASE); 1197 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 1198 while (bcnt < CURSOR_MAX_SIZE * 16) { 1199 img = *ip++; 1200 msk = *mp++; 1201 img &= msk; /* cookie off image */ 1202 u = (msk & 0x0f) << 4 | (img & 0x0f); 1203 REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]); 1204 tc_wmb(); 1205 u = (msk & 0xf0) | (img & 0xf0) >> 4; 1206 REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]); 1207 tc_wmb(); 1208 bcnt += 2; 1209 } 1210 } 1211 1212 if ((v & SI_CMAP_CHANGED) != 0) { 1213 struct stic_hwcmap256 *cm; 1214 int index; 1215 1216 cm = &si->si_cmap; 1217 1218 SELECT(vdac, 0); 1219 SELECT(vdac, 0); 1220 for (index = 0; index < CMAP_SIZE; index++) { 1221 REG(vdac, bt_cmap) = DUPBYTE0(cm->r[index]); 1222 tc_wmb(); 1223 REG(vdac, bt_cmap) = DUPBYTE0(cm->g[index]); 1224 tc_wmb(); 1225 REG(vdac, bt_cmap) = DUPBYTE0(cm->b[index]); 1226 tc_wmb(); 1227 } 1228 } 1229} 1230 1231static int 1232stic_get_cmap(struct stic_info *si, struct wsdisplay_cmap *p) 1233{ 1234 u_int index = p->index, count = p->count; 1235 int error; 1236 1237 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 1238 return (EINVAL); 1239 1240 error = copyout(&si->si_cmap.r[index], p->red, count); 1241 if (error) 1242 return error; 1243 error = copyout(&si->si_cmap.g[index], p->green, count); 1244 if (error) 1245 return error; 1246 error = copyout(&si->si_cmap.b[index], p->blue, count); 1247 return error; 1248} 1249 1250static int 1251stic_set_cmap(struct stic_info *si, struct wsdisplay_cmap *p) 1252{ 1253 struct stic_hwcmap256 cmap; 1254 u_int index, count; 1255 int s, error; 1256 1257 index = p->index; 1258 count = p->count; 1259 1260 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 1261 return (EINVAL); 1262 1263 error = copyin(p->red, &cmap.r[index], count); 1264 if (error) 1265 return error; 1266 error = copyin(p->green, &cmap.g[index], count); 1267 if (error) 1268 return error; 1269 error = copyin(p->blue, &cmap.b[index], count); 1270 if (error) 1271 return error; 1272 1273 s = spltty(); 1274 memcpy(&si->si_cmap.r[index], &cmap.r[index], count); 1275 memcpy(&si->si_cmap.g[index], &cmap.g[index], count); 1276 memcpy(&si->si_cmap.b[index], &cmap.b[index], count); 1277 si->si_flags |= SI_CMAP_CHANGED; 1278 splx(s); 1279 1280 /* 1281 * XXX Since we don't yet receive vblank interrupts from the PXG, we 1282 * must flush immediately. 1283 */ 1284 if (si->si_disptype == WSDISPLAY_TYPE_PXG) 1285 stic_flush(si); 1286 1287 return (0); 1288} 1289 1290static int 1291stic_set_cursor(struct stic_info *si, struct wsdisplay_cursor *p) 1292{ 1293#define cc (&si->si_cursor) 1294 u_int v, index = 0, count = 0, icount = 0; 1295 struct stic_screen *ss; 1296 uint8_t r[2], g[2], b[2], image[512], mask[512]; 1297 int s, error; 1298 1299 v = p->which; 1300 ss = si->si_curscreen; 1301 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) { 1302 index = p->cmap.index; 1303 count = p->cmap.count; 1304 if (index >= 2 || count > 2 - index) 1305 return (EINVAL); 1306 error = copyin(p->cmap.red, &r[index], count); 1307 if (error) 1308 return error; 1309 error = copyin(p->cmap.green, &g[index], count); 1310 if (error) 1311 return error; 1312 error = copyin(p->cmap.blue, &b[index], count); 1313 if (error) 1314 return error; 1315 } 1316 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) { 1317 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 1318 return (EINVAL); 1319 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 1320 error = copyin(p->image, image, icount); 1321 if (error) 1322 return error; 1323 error = copyin(p->mask, mask, icount); 1324 if (error) 1325 return error; 1326 } 1327 if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) != 0) { 1328 if (v & WSDISPLAY_CURSOR_DOCUR) 1329 cc->cc_hot = p->hot; 1330 if (v & WSDISPLAY_CURSOR_DOPOS) 1331 stic_set_curpos(si, &p->pos); 1332 } 1333 1334 s = spltty(); 1335 if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) { 1336 if (p->enable) 1337 ss->ss_flags |= SS_CURENB; 1338 else 1339 ss->ss_flags &= ~SS_CURENB; 1340 si->si_flags |= SI_CURENB_CHANGED; 1341 } 1342 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) { 1343 memcpy(&cc->cc_color[index], &r[index], count); 1344 memcpy(&cc->cc_color[index + 2], &g[index], count); 1345 memcpy(&cc->cc_color[index + 4], &b[index], count); 1346 si->si_flags |= SI_CURCMAP_CHANGED; 1347 } 1348 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) { 1349 memset(cc->cc_image, 0, sizeof cc->cc_image); 1350 memcpy(cc->cc_image, image, icount); 1351 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 1352 memcpy(cc->cc_mask, mask, icount); 1353 si->si_flags |= SI_CURSHAPE_CHANGED; 1354 } 1355 splx(s); 1356 1357 /* 1358 * XXX Since we don't yet receive vblank interrupts from the PXG, we 1359 * must flush immediately. 1360 */ 1361 if (si->si_disptype == WSDISPLAY_TYPE_PXG) 1362 stic_flush(si); 1363 1364 return (0); 1365#undef cc 1366} 1367 1368static int 1369stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p) 1370{ 1371 1372 /* XXX */ 1373 return (EPASSTHROUGH); 1374} 1375 1376static void 1377stic_set_curpos(struct stic_info *si, struct wsdisplay_curpos *curpos) 1378{ 1379 int x, y; 1380 1381 x = curpos->x; 1382 y = curpos->y; 1383 1384 if (y < 0) 1385 y = 0; 1386 else if (y > 1023) 1387 y = 1023; 1388 if (x < 0) 1389 x = 0; 1390 else if (x > 1279) 1391 x = 1279; 1392 1393 si->si_cursor.cc_pos.x = x; 1394 si->si_cursor.cc_pos.y = y; 1395 stic_set_hwcurpos(si); 1396} 1397 1398static void 1399stic_set_hwcurpos(struct stic_info *si) 1400{ 1401 volatile uint32_t *vdac; 1402 int x, y, s; 1403 1404 vdac = si->si_vdac; 1405 1406 x = si->si_cursor.cc_pos.x - si->si_cursor.cc_hot.x; 1407 y = si->si_cursor.cc_pos.y - si->si_cursor.cc_hot.y; 1408 x += STIC_MAGIC_X; 1409 y += STIC_MAGIC_Y; 1410 1411 s = spltty(); 1412 SELECT(vdac, BT459_IREG_CURSOR_X_LOW); 1413 REG(vdac, bt_reg) = DUPBYTE0(x); tc_wmb(); 1414 REG(vdac, bt_reg) = DUPBYTE1(x); tc_wmb(); 1415 REG(vdac, bt_reg) = DUPBYTE0(y); tc_wmb(); 1416 REG(vdac, bt_reg) = DUPBYTE1(y); tc_wmb(); 1417 splx(s); 1418} 1419 1420/* 1421 * STIC control interface. We have a separate device for mapping the board, 1422 * because access to the DMA engine means that it's possible to circumvent 1423 * the securelevel mechanism. 1424 */ 1425static int 1426sticopen(dev_t dev, int flag, int mode, struct lwp *l) 1427{ 1428 struct stic_info *si; 1429 int s, error; 1430 1431 error = kauth_authorize_device_passthru(l->l_cred, dev, 1432 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, NULL); 1433 if (error) 1434 return (error); 1435 if (minor(dev) >= STIC_MAXDV) 1436 return (ENXIO); 1437 if ((si = stic_info[minor(dev)]) == NULL) 1438 return (ENXIO); 1439 1440 s = spltty(); 1441 if ((si->si_flags & SI_DVOPEN) != 0) { 1442 splx(s); 1443 return (EBUSY); 1444 } 1445 si->si_flags |= SI_DVOPEN; 1446 splx(s); 1447 1448 return (0); 1449} 1450 1451static int 1452sticclose(dev_t dev, int flag, int mode, struct lwp *l) 1453{ 1454 struct stic_info *si; 1455 int s; 1456 1457 si = stic_info[minor(dev)]; 1458 s = spltty(); 1459 si->si_flags &= ~SI_DVOPEN; 1460 splx(s); 1461 1462 return (0); 1463} 1464 1465static paddr_t 1466sticmmap(dev_t dev, off_t offset, int prot) 1467{ 1468 struct stic_info *si; 1469 struct stic_xmap *sxm; 1470 paddr_t pa; 1471 1472 si = stic_info[minor(dev)]; 1473 sxm = NULL; 1474 1475 if (si->si_dispmode != WSDISPLAYIO_MODE_MAPPED) 1476 return (-1L); 1477 1478 if (offset < 0) 1479 return ((paddr_t)-1L); 1480 1481 if (offset < sizeof(sxm->sxm_stic)) { 1482 pa = STIC_KSEG_TO_PHYS(si->si_stic); 1483 return (machine_btop(pa + offset)); 1484 } 1485 offset -= sizeof(sxm->sxm_stic); 1486 1487 if (offset < sizeof(sxm->sxm_poll)) { 1488 pa = STIC_KSEG_TO_PHYS(si->si_slotbase); 1489 return (machine_btop(pa + offset)); 1490 } 1491 offset -= sizeof(sxm->sxm_poll); 1492 1493 if (offset < si->si_buf_size) 1494 return (machine_btop(si->si_buf_phys + offset)); 1495 1496 return ((paddr_t)-1L); 1497} 1498