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