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