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