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