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