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