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