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