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
124 static int sticioctl(void *, void *, u_long, void *, int, struct lwp *);
125 static int stic_alloc_screen(void *, const struct wsscreen_descr *,
126 void **, int *, int *, long *);
127 static void stic_free_screen(void *, void *);
128 static int stic_show_screen(void *, void *, int,
129 void (*)(void *, int, int), void *);
130
131 static void stic_do_switch(void *);
132 static void stic_setup_backing(struct stic_info *, struct stic_screen *);
133 static void stic_setup_vdac(struct stic_info *);
134 static void stic_clear_screen(struct stic_info *);
135
136 static int stic_get_cmap(struct stic_info *, struct wsdisplay_cmap *);
137 static int stic_set_cmap(struct stic_info *, struct wsdisplay_cmap *);
138 static int stic_set_cursor(struct stic_info *, struct wsdisplay_cursor *);
139 static int stic_get_cursor(struct stic_info *, struct wsdisplay_cursor *);
140 static void stic_set_curpos(struct stic_info *, struct wsdisplay_curpos *);
141 static void stic_set_hwcurpos(struct stic_info *);
142
143 static void stic_cursor(void *, int, int, int);
144 static void stic_copycols(void *, int, int, int, int);
145 static void stic_copyrows(void *, int, int, int);
146 static void stic_erasecols(void *, int, int, int, long);
147 static void stic_eraserows(void *, int, int, long);
148 static int stic_mapchar(void *, int, u_int *);
149 static void stic_putchar(void *, int, int, u_int, long);
150 static int stic_allocattr(void *, int, int, int, long *);
151
152 static dev_type_open(sticopen);
153 static dev_type_close(sticclose);
154 static dev_type_mmap(sticmmap);
155
156 const struct cdevsw stic_cdevsw = {
157 .d_open = sticopen,
158 .d_close = sticclose,
159 .d_read = noread,
160 .d_write = nowrite,
161 .d_ioctl = noioctl,
162 .d_stop = nostop,
163 .d_tty = notty,
164 .d_poll = nopoll,
165 .d_mmap = sticmmap,
166 .d_kqfilter = nokqfilter,
167 .d_discard = nodiscard,
168 .d_flag = 0
169 };
170
171 /* Colormap for wscons, matching WSCOL_*. Upper 8 are high-intensity. */
172 static const uint8_t stic_cmap[16*3] = {
173 0x00, 0x00, 0x00, /* black */
174 0x7f, 0x00, 0x00, /* red */
175 0x00, 0x7f, 0x00, /* green */
176 0x7f, 0x7f, 0x00, /* brown */
177 0x00, 0x00, 0x7f, /* blue */
178 0x7f, 0x00, 0x7f, /* magenta */
179 0x00, 0x7f, 0x7f, /* cyan */
180 0xc7, 0xc7, 0xc7, /* white */
181
182 0x7f, 0x7f, 0x7f, /* black */
183 0xff, 0x00, 0x00, /* red */
184 0x00, 0xff, 0x00, /* green */
185 0xff, 0xff, 0x00, /* brown */
186 0x00, 0x00, 0xff, /* blue */
187 0xff, 0x00, 0xff, /* magenta */
188 0x00, 0xff, 0xff, /* cyan */
189 0xff, 0xff, 0xff, /* white */
190 };
191
192 /*
193 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
194 * M M M M I I I I M I M I M I M I
195 * [ before ] [ after ]
196 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
197 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
198 */
199 static const uint8_t shuffle[256] = {
200 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
201 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
202 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
203 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
204 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
205 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
206 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
207 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
208 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
209 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
210 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
211 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
212 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
213 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
214 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
215 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
216 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
217 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
218 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
219 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
220 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
221 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
222 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
223 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
224 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
225 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
226 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
227 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
228 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
229 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
230 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
231 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
232 };
233
234 static const struct wsdisplay_accessops stic_accessops = {
235 sticioctl,
236 NULL, /* mmap */
237 stic_alloc_screen,
238 stic_free_screen,
239 stic_show_screen,
240 NULL, /* load_font */
241 };
242
243 static const struct wsdisplay_emulops stic_emulops = {
244 stic_cursor,
245 stic_mapchar,
246 stic_putchar,
247 stic_copycols,
248 stic_erasecols,
249 stic_copyrows,
250 stic_eraserows,
251 stic_allocattr
252 };
253
254 static struct wsscreen_descr stic_stdscreen = {
255 "std",
256 0, 0,
257 &stic_emulops,
258 0, 0,
259 WSSCREEN_WSCOLORS | WSSCREEN_HILIT
260 };
261
262 static const struct wsscreen_descr *_stic_scrlist[] = {
263 &stic_stdscreen,
264 };
265
266 static const struct wsscreen_list stic_screenlist = {
267 sizeof(_stic_scrlist) / sizeof(struct wsscreen_descr *), _stic_scrlist
268 };
269
270 struct stic_info stic_consinfo;
271 static struct stic_screen stic_consscr;
272 static struct stic_info *stic_info[STIC_MAXDV];
273 static int stic_unit;
274
275 void
stic_init(struct stic_info * si)276 stic_init(struct stic_info *si)
277 {
278 volatile uint32_t *vdac;
279 int i, cookie;
280
281 /* Reset the STIC & stamp(s). */
282 stic_reset(si);
283 vdac = si->si_vdac;
284
285 /* Hit it... */
286 SELECT(vdac, BT459_IREG_COMMAND_0);
287 REG(vdac, bt_reg) = 0x00c0c0c0; tc_wmb();
288
289 /* Now reset the VDAC. */
290 *si->si_vdac_reset = 0;
291 tc_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
stic_reset(struct stic_info * si)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_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
405 void
stic_attach(device_t self,struct stic_info * si,int console)406 stic_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
435 void
stic_cnattach(struct stic_info * si)436 stic_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
454 static void
stic_setup_vdac(struct stic_info * si)455 stic_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
504 static void
stic_clear_screen(struct stic_info * si)505 stic_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
530 static int
sticioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)531 sticioctl(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
616 static void
stic_setup_backing(struct stic_info * si,struct stic_screen * ss)617 stic_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
625 static int
stic_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * attrp)626 stic_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
652 static void
stic_free_screen(void * v,void * cookie)653 stic_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
670 static int
stic_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)671 stic_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
692 static void
stic_do_switch(void * cookie)693 stic_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
760 static int
stic_allocattr(void * cookie,int fg,int bg,int flags,long * attr)761 stic_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
781 static void
stic_erasecols(void * cookie,int row,int col,int num,long attr)782 stic_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
822 static void
stic_eraserows(void * cookie,int row,int num,long attr)823 stic_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
861 static void
stic_copyrows(void * cookie,int src,int dst,int height)862 stic_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
921 static void
stic_copycols(void * cookie,int row,int src,int dst,int num)922 stic_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
973 static void
stic_putchar(void * cookie,int r,int c,u_int uc,long attr)974 stic_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
1093 static int
stic_mapchar(void * cookie,int c,u_int * cp)1094 stic_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
1114 static void
stic_cursor(void * cookie,int on,int row,int col)1115 stic_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
1151 void
stic_flush(struct stic_info * si)1152 stic_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
1231 static int
stic_get_cmap(struct stic_info * si,struct wsdisplay_cmap * p)1232 stic_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
1250 static int
stic_set_cmap(struct stic_info * si,struct wsdisplay_cmap * p)1251 stic_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
1290 static int
stic_set_cursor(struct stic_info * si,struct wsdisplay_cursor * p)1291 stic_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
1368 static int
stic_get_cursor(struct stic_info * si,struct wsdisplay_cursor * p)1369 stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1370 {
1371
1372 /* XXX */
1373 return (EPASSTHROUGH);
1374 }
1375
1376 static void
stic_set_curpos(struct stic_info * si,struct wsdisplay_curpos * curpos)1377 stic_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
1398 static void
stic_set_hwcurpos(struct stic_info * si)1399 stic_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 */
1425 static int
sticopen(dev_t dev,int flag,int mode,struct lwp * l)1426 sticopen(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
1451 static int
sticclose(dev_t dev,int flag,int mode,struct lwp * l)1452 sticclose(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
1465 static paddr_t
sticmmap(dev_t dev,off_t offset,int prot)1466 sticmmap(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