stic.c revision 1.14 1 /* $NetBSD: stic.c,v 1.14 2002/02/11 10:44:40 wiz 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.14 2002/02/11 10:44:40 wiz 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_alloc_attr(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_alloc_attr
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 cookie = wsfont_find(NULL, 0, 0, 0);
342
343 if (wsfont_lock(cookie, &si->si_font,
344 WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0)
345 panic("stic_init: couldn't lock font\n");
346
347 si->si_fontw = si->si_font->fontwidth;
348 si->si_fonth = si->si_font->fontheight;
349 si->si_consw = (1280 / si->si_fontw) & ~1;
350 si->si_consh = 1024 / si->si_fonth;
351 stic_stdscreen.ncols = si->si_consw;
352 stic_stdscreen.nrows = si->si_consh;
353
354 #ifdef DIAGNOSTIC
355 if ((u_int)si->si_fonth > 32 || (u_int)si->si_fontw > 16)
356 panic("stic_init: unusable font");
357 #endif
358
359 stic_setup_vdac(si);
360 stic_clear_screen(si);
361 si->si_dispmode = WSDISPLAYIO_MODE_EMUL;
362 }
363
364 void
365 stic_reset(struct stic_info *si)
366 {
367 int modtype, xconfig, yconfig, config;
368 volatile struct stic_regs *sr;
369
370 sr = si->si_stic;
371
372 /*
373 * Initialize the interface chip registers.
374 */
375 sr->sr_sticsr = 0x00000030; /* Get the STIC's attention. */
376 tc_wmb();
377 tc_syncbus();
378 DELAY(2000); /* wait 2ms for STIC to respond. */
379 sr->sr_sticsr = 0x00000000; /* Hit the STIC's csr again... */
380 tc_wmb();
381 sr->sr_buscsr = 0xffffffff; /* and bash its bus-acess csr. */
382 tc_wmb();
383 tc_syncbus(); /* Blam! */
384 DELAY(20000); /* wait until the stic recovers... */
385
386 modtype = sr->sr_modcl;
387 xconfig = (modtype & 0x800) >> 11;
388 yconfig = (modtype & 0x600) >> 9;
389 config = (yconfig << 1) | xconfig;
390 si->si_stampw = (xconfig ? 5 : 4);
391 si->si_stamph = (1 << yconfig);
392 #ifdef notyet
393 si->si_option = (char)((modtype >> 12) & 3);
394 #endif
395
396 /* First PixelStamp */
397 si->si_stamp[0x000b0] = config;
398 si->si_stamp[0x000b4] = 0x0;
399
400 /* Second PixelStamp */
401 if (yconfig > 0) {
402 si->si_stamp[0x100b0] = config | 8;
403 si->si_stamp[0x100b4] = 0;
404 }
405
406 /*
407 * Initialize STIC video registers. Enable error and vertical
408 * retrace interrupts. Set the packet done flag so the Xserver will
409 * not time-out on the first packet submitted.
410 */
411 sr->sr_vblank = (1024 << 16) | 1063;
412 sr->sr_vsync = (1027 << 16) | 1030;
413 sr->sr_hblank = (255 << 16) | 340;
414 sr->sr_hsync2 = 245;
415 sr->sr_hsync = (261 << 16) | 293;
416 sr->sr_ipdvint =
417 STIC_INT_WE | STIC_INT_P | STIC_INT_E_EN | STIC_INT_V_EN;
418 sr->sr_sticsr = 8;
419 tc_wmb();
420 tc_syncbus();
421 }
422
423 void
424 stic_attach(struct device *self, struct stic_info *si, int console)
425 {
426 struct wsemuldisplaydev_attach_args waa;
427
428 if (stic_unit < STIC_MAXDV) {
429 stic_info[stic_unit] = si;
430 si->si_unit = stic_unit++;
431 } else
432 si->si_unit = -1;
433
434 callout_init(&si->si_switch_callout);
435
436 /*
437 * Allocate backing for the console. We could trawl back through
438 * msgbuf and and fill the backing, but it's not worth the hassle.
439 * We could also grab backing using pmap_steal_memory() early on,
440 * but that's a little ugly.
441 */
442 if (console)
443 stic_setup_backing(si, &stic_consscr);
444
445 waa.console = console;
446 waa.scrdata = &stic_screenlist;
447 waa.accessops = &stic_accessops;
448 waa.accesscookie = si;
449
450 config_found(self, &waa, wsemuldisplaydevprint);
451 }
452
453 void
454 stic_cnattach(struct stic_info *si)
455 {
456 struct stic_screen *ss;
457 long defattr;
458
459 ss = &stic_consscr;
460 si->si_curscreen = ss;
461 ss->ss_flags = SS_ALLOCED | SS_ACTIVE | SS_CURENB;
462 ss->ss_si = si;
463
464 si->si_flags |= SI_CURENB_CHANGED;
465 stic_flush(si);
466
467 stic_alloc_attr(ss, 0, 0, 0, &defattr);
468 stic_eraserows(ss, 0, si->si_consh, 0);
469 wsdisplay_cnattach(&stic_stdscreen, ss, 0, 0, defattr);
470 }
471
472 void
473 stic_setup_vdac(struct stic_info *si)
474 {
475 u_int8_t *ip, *mp;
476 int r, c, o, b, i, s;
477
478 s = spltty();
479
480 ip = (u_int8_t *)si->si_cursor.cc_image;
481 mp = ip + (sizeof(si->si_cursor.cc_image) >> 1);
482 memset(ip, 0, sizeof(si->si_cursor.cc_image));
483
484 for (r = 0; r < si->si_fonth; r++) {
485 for (c = r & 1; c < si->si_fontw; c += 2) {
486 o = c >> 3;
487 b = 1 << (c & 7);
488 ip[o] |= b;
489 mp[o] |= b;
490 }
491
492 ip += 8;
493 mp += 8;
494 }
495
496 si->si_cursor.cc_size.x = 64;
497 si->si_cursor.cc_size.y = si->si_fonth;
498 si->si_cursor.cc_hot.x = 0;
499 si->si_cursor.cc_hot.y = 0;
500
501 si->si_cursor.cc_color[0] = 0xff;
502 si->si_cursor.cc_color[2] = 0xff;
503 si->si_cursor.cc_color[4] = 0xff;
504 si->si_cursor.cc_color[1] = 0x00;
505 si->si_cursor.cc_color[3] = 0x00;
506 si->si_cursor.cc_color[5] = 0x00;
507
508 memset(&si->si_cmap, 0, sizeof(si->si_cmap));
509 for (i = 0; i < 16; i++) {
510 si->si_cmap.r[i] = stic_cmap[i*3 + 0];
511 si->si_cmap.g[i] = stic_cmap[i*3 + 1];
512 si->si_cmap.b[i] = stic_cmap[i*3 + 2];
513 }
514
515 si->si_flags |= SI_CMAP_CHANGED | SI_CURSHAPE_CHANGED |
516 SI_CURCMAP_CHANGED;
517
518 splx(s);
519 }
520
521 void
522 stic_clear_screen(struct stic_info *si)
523 {
524 u_int32_t *pb;
525 int i;
526
527 /*
528 * Do this twice, since the first packet after a reset may be
529 * silently ignored.
530 */
531 for (i = 0; i < 2; i++) {
532 pb = (*si->si_pbuf_get)(si);
533
534 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
535 pb[1] = 0x01ffffff;
536 pb[2] = 0;
537 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
538 pb[4] = (1024 << 2) - 1;
539 pb[5] = 0;
540 pb[6] = 0;
541 pb[7] = (1280 << 19) | ((1024 << 3) + pb[4]);
542
543 (*si->si_pbuf_post)(si, pb);
544 }
545 }
546
547 int
548 sticioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
549 {
550 struct stic_info *si;
551
552 si = v;
553
554 switch (cmd) {
555 case WSDISPLAYIO_GTYPE:
556 *(u_int *)data = si->si_disptype;
557 return (0);
558
559 case WSDISPLAYIO_GINFO:
560 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
561 wsd_fbip->height = 1024;
562 wsd_fbip->width = 1280;
563 wsd_fbip->depth = si->si_depth == 8 ? 8 : 32;
564 wsd_fbip->cmsize = CMAP_SIZE;
565 #undef fbt
566 return (0);
567
568 case WSDISPLAYIO_GETCMAP:
569 return (stic_get_cmap(si, (struct wsdisplay_cmap *)data));
570
571 case WSDISPLAYIO_PUTCMAP:
572 return (stic_set_cmap(si, (struct wsdisplay_cmap *)data));
573
574 case WSDISPLAYIO_SVIDEO:
575 #if 0 /* XXX later */
576 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
577 if ((si->si_blanked == 0) ^ turnoff)
578 si->si_blanked = turnoff;
579 #endif
580 return (0);
581
582 case WSDISPLAYIO_GVIDEO:
583 #if 0 /* XXX later */
584 *(u_int *)data = si->si_blanked ?
585 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
586 #endif
587 return (0);
588
589 case WSDISPLAYIO_GCURPOS:
590 *(struct wsdisplay_curpos *)data = si->si_cursor.cc_pos;
591 return (0);
592
593 case WSDISPLAYIO_SCURPOS:
594 stic_set_curpos(si, (struct wsdisplay_curpos *)data);
595 return (0);
596
597 case WSDISPLAYIO_GCURMAX:
598 ((struct wsdisplay_curpos *)data)->x =
599 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
600 return (0);
601
602 case WSDISPLAYIO_GCURSOR:
603 return (stic_get_cursor(si, (struct wsdisplay_cursor *)data));
604
605 case WSDISPLAYIO_SCURSOR:
606 return (stic_set_cursor(si, (struct wsdisplay_cursor *)data));
607
608 case WSDISPLAYIO_SMODE:
609 si->si_dispmode = *(int *)data;
610 if (si->si_dispmode == WSDISPLAYIO_MODE_EMUL) {
611 (*si->si_ioctl)(si, STICIO_STOPQ, NULL, flag, p);
612 stic_setup_vdac(si);
613 stic_flush(si);
614 stic_clear_screen(si);
615 stic_do_switch(si->si_curscreen);
616 }
617 return (0);
618
619 case STICIO_RESET:
620 stic_reset(si);
621 return (0);
622 }
623
624 if (si->si_ioctl != NULL)
625 return ((*si->si_ioctl)(si, cmd, data, flag, p));
626
627 return (ENOTTY);
628 }
629
630 void
631 stic_setup_backing(struct stic_info *si, struct stic_screen *ss)
632 {
633 int size;
634
635 size = si->si_consw * si->si_consh * sizeof(*ss->ss_backing);
636 ss->ss_backing = malloc(size, M_DEVBUF, M_NOWAIT|M_ZERO);
637 }
638
639 int
640 stic_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
641 int *curxp, int *curyp, long *attrp)
642 {
643 struct stic_info *si;
644 struct stic_screen *ss;
645
646 si = (struct stic_info *)v;
647
648 if ((stic_consscr.ss_flags & SS_ALLOCED) == 0)
649 ss = &stic_consscr;
650 else {
651 ss = malloc(sizeof(*ss), M_DEVBUF, M_WAITOK|M_ZERO);
652 }
653 stic_setup_backing(si, ss);
654
655 ss->ss_si = si;
656 ss->ss_flags = SS_ALLOCED | SS_CURENB;
657
658 *cookiep = ss;
659 *curxp = 0;
660 *curyp = 0;
661
662 stic_alloc_attr(ss, 0, 0, 0, attrp);
663 return (0);
664 }
665
666 void
667 stic_free_screen(void *v, void *cookie)
668 {
669 struct stic_screen *ss;
670
671 ss = cookie;
672
673 #ifdef DIAGNOSTIC
674 if (ss == &stic_consscr)
675 panic("stic_free_screen: console");
676 if (ss == ((struct stic_info *)v)->si_curscreen)
677 panic("stic_free_screen: freeing current screen");
678 #endif
679
680 free(ss->ss_backing, M_DEVBUF);
681 free(ss, M_DEVBUF);
682 }
683
684 int
685 stic_show_screen(void *v, void *cookie, int waitok,
686 void (*cb)(void *, int, int), void *cbarg)
687 {
688 struct stic_info *si;
689
690 si = (struct stic_info *)v;
691 if (si->si_switchcbarg != NULL)
692 return (EAGAIN);
693 si->si_switchcb = cb;
694 si->si_switchcbarg = cbarg;
695
696 if (cb != NULL) {
697 callout_reset(&si->si_switch_callout, 0, stic_do_switch,
698 cookie);
699 return (EAGAIN);
700 }
701
702 stic_do_switch(cookie);
703 return (0);
704 }
705
706 void
707 stic_do_switch(void *cookie)
708 {
709 struct stic_screen *ss;
710 struct stic_info *si;
711 u_int r, c, nr, nc;
712 u_int16_t *p, *sp;
713
714 ss = cookie;
715 si = ss->ss_si;
716
717 #ifdef DIAGNOSTIC
718 if (ss->ss_backing == NULL)
719 panic("stic_do_switch: screen not backed");
720 #endif
721
722 /* Swap in the new screen, and temporarily disable its backing. */
723 if (si->si_curscreen != NULL)
724 si->si_curscreen->ss_flags ^= SS_ACTIVE;
725 si->si_curscreen = ss;
726 ss->ss_flags |= SS_ACTIVE;
727 sp = ss->ss_backing;
728 ss->ss_backing = NULL;
729
730 /*
731 * We assume that most of the screen is blank and blast it with
732 * eraserows(), because eraserows() is cheap.
733 */
734 nr = si->si_consh;
735 stic_eraserows(ss, 0, nr, 0);
736
737 nc = si->si_consw;
738 p = sp;
739 for (r = 0; r < nr; r++)
740 for (c = 0; c < nc; c += 2, p += 2) {
741 if ((p[0] & 0xfff0) != 0)
742 stic_putchar(ss, r, c, p[0] >> 8,
743 p[0] & 0x00ff);
744 if ((p[1] & 0xfff0) != 0)
745 stic_putchar(ss, r, c + 1, p[1] >> 8,
746 p[1] & 0x00ff);
747 }
748
749 /*
750 * Re-enable the screen's backing, and move the cursor to the
751 * correct spot.
752 */
753 ss->ss_backing = sp;
754 si->si_cursor.cc_pos.x = ss->ss_curx;
755 si->si_cursor.cc_pos.y = ss->ss_cury;
756 stic_set_hwcurpos(si);
757 si->si_flags |= SI_CURENB_CHANGED;
758
759 /*
760 * XXX Since we don't yet receive vblank interrupts from the
761 * PXG, we must flush immediatley.
762 */
763 if (si->si_disptype == WSDISPLAY_TYPE_PXG)
764 stic_flush(si);
765
766 /* Tell wscons that we're done. */
767 if (si->si_switchcbarg != NULL) {
768 cookie = si->si_switchcbarg;
769 si->si_switchcbarg = NULL;
770 (*si->si_switchcb)(cookie, 0, 0);
771 }
772 }
773
774 int
775 stic_alloc_attr(void *cookie, int fg, int bg, int flags, long *attr)
776 {
777 long tmp;
778
779 if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0)
780 return (EINVAL);
781
782 if ((flags & WSATTR_WSCOLORS) == 0) {
783 fg = 7;
784 bg = 0;
785 }
786
787 if ((flags & WSATTR_HILIT) != 0)
788 fg += 8;
789
790 tmp = fg | (bg << 4);
791 *attr = tmp | (tmp << 16);
792 return (0);
793 }
794
795 void
796 stic_erasecols(void *cookie, int row, int col, int num, long attr)
797 {
798 struct stic_info *si;
799 struct stic_screen *ss;
800 u_int32_t *pb;
801 u_int i, linewidth;
802 u_int16_t *p;
803
804 ss = cookie;
805 si = ss->ss_si;
806
807 if (ss->ss_backing != NULL) {
808 p = ss->ss_backing + row * si->si_consw + col;
809 for (i = num; i != 0; i--)
810 *p++ = (u_int16_t)attr;
811 }
812 if ((ss->ss_flags & SS_ACTIVE) == 0)
813 return;
814
815 col = (col * si->si_fontw) << 19;
816 num = (num * si->si_fontw) << 19;
817 row = row * si->si_fonth;
818 attr = (attr & 0xf0) >> 4;
819 linewidth = (si->si_fonth << 2) - 1;
820 row = (row << 3) + linewidth;
821
822 pb = (*si->si_pbuf_get)(si);
823
824 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
825 pb[1] = 0x01ffffff;
826 pb[2] = 0;
827 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
828 pb[4] = linewidth;
829 pb[5] = DUPBYTE0(attr);
830 pb[6] = col | row;
831 pb[7] = (col + num) | row;
832
833 (*si->si_pbuf_post)(si, pb);
834 }
835
836 void
837 stic_eraserows(void *cookie, int row, int num, long attr)
838 {
839 struct stic_info *si;
840 struct stic_screen *ss;
841 u_int linewidth, i;
842 u_int32_t *pb;
843
844 ss = cookie;
845 si = ss->ss_si;
846
847 if (ss->ss_backing != NULL) {
848 pb = (u_int32_t *)(ss->ss_backing + row * si->si_consw);
849 for (i = si->si_consw * num; i > 0; i -= 2)
850 *pb++ = (u_int32_t)attr;
851 }
852 if ((ss->ss_flags & SS_ACTIVE) == 0)
853 return;
854
855 row *= si->si_fonth;
856 num *= si->si_fonth;
857 attr = (attr & 0xf0) >> 4;
858 linewidth = (num << 2) - 1;
859 row = (row << 3) + linewidth;
860
861 pb = (*si->si_pbuf_get)(si);
862
863 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
864 pb[1] = 0x01ffffff;
865 pb[2] = 0;
866 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
867 pb[4] = linewidth;
868 pb[5] = DUPBYTE0(attr);
869 pb[6] = row;
870 pb[7] = (1280 << 19) | row;
871
872 (*si->si_pbuf_post)(si, pb);
873 }
874
875 void
876 stic_copyrows(void *cookie, int src, int dst, int height)
877 {
878 struct stic_info *si;
879 struct stic_screen *ss;
880 u_int32_t *pb, *pbs;
881 u_int num, inc, adj;
882
883 ss = cookie;
884 si = ss->ss_si;
885
886 if (ss->ss_backing != NULL)
887 bcopy(ss->ss_backing + src * si->si_consw,
888 ss->ss_backing + dst * si->si_consw,
889 si->si_consw * sizeof(*ss->ss_backing) * height);
890 if ((ss->ss_flags & SS_ACTIVE) == 0)
891 return;
892
893 /*
894 * We need to do this in reverse if the destination row is below
895 * the source.
896 */
897 if (dst > src) {
898 src += height;
899 dst += height;
900 inc = -8;
901 adj = -1;
902 } else {
903 inc = 8;
904 adj = 0;
905 }
906
907 src = (src * si->si_fonth + adj) << 3;
908 dst = (dst * si->si_fonth + adj) << 3;
909 height *= si->si_fonth;
910
911 while (height > 0) {
912 num = (height < 255 ? height : 255);
913 height -= num;
914
915 pbs = (*si->si_pbuf_get)(si);
916 pb = pbs;
917
918 pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
919 pb[1] = (num << 24) | 0xffffff;
920 pb[2] = 0x0;
921 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN |
922 STAMP_COPYSPAN_ALIGNED;
923 pb[4] = 1; /* linewidth */
924
925 for (; num != 0; num--, src += inc, dst += inc, pb += 3) {
926 pb[5] = 1280 << 3;
927 pb[6] = src;
928 pb[7] = dst;
929 }
930
931 (*si->si_pbuf_post)(si, pbs);
932 }
933 }
934
935 void
936 stic_copycols(void *cookie, int row, int src, int dst, int num)
937 {
938 struct stic_info *si;
939 struct stic_screen *ss;
940 u_int height, updword;
941 u_int32_t *pb, *pbs;
942
943 ss = cookie;
944 si = ss->ss_si;
945
946 if (ss->ss_backing != NULL)
947 bcopy(ss->ss_backing + row * si->si_consw + src,
948 ss->ss_backing + row * si->si_consw + dst,
949 num * sizeof(*ss->ss_backing));
950 if ((ss->ss_flags & SS_ACTIVE) == 0)
951 return;
952
953 /*
954 * The stamp reads and writes left -> right only, so we need to
955 * buffer the span if the source and destination regions overlap
956 * and the source is left of the destination.
957 */
958 updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN;
959
960 if (src < dst && src + num > dst)
961 updword |= STAMP_HALF_BUFF;
962
963 row = (row * si->si_fonth) << 3;
964 num = (num * si->si_fontw) << 3;
965 src = row | ((src * si->si_fontw) << 19);
966 dst = row | ((dst * si->si_fontw) << 19);
967 height = si->si_fonth;
968
969 pbs = (*si->si_pbuf_get)(si);
970 pb = pbs;
971
972 pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
973 pb[1] = (height << 24) | 0xffffff;
974 pb[2] = 0x0;
975 pb[3] = updword;
976 pb[4] = 1; /* linewidth */
977
978 for ( ; height != 0; height--, src += 8, dst += 8, pb += 3) {
979 pb[5] = num;
980 pb[6] = src;
981 pb[7] = dst;
982 }
983
984 (*si->si_pbuf_post)(si, pbs);
985 }
986
987 void
988 stic_putchar(void *cookie, int r, int c, u_int uc, long attr)
989 {
990 struct wsdisplay_font *font;
991 struct stic_screen *ss;
992 struct stic_info *si;
993 u_int i, bgcolor, fgcolor;
994 u_int *pb, v1, v2, xya;
995 u_short *fr;
996
997 ss = cookie;
998 si = ss->ss_si;
999
1000 /* It's cheaper to use erasecols() to blit blanks. */
1001 if (uc == 0) {
1002 stic_erasecols(cookie, r, c, 1, attr);
1003 return;
1004 }
1005
1006 if (ss->ss_backing != NULL)
1007 ss->ss_backing[r * si->si_consw + c] =
1008 (u_short)((attr & 0xff) | (uc << 8));
1009 if ((ss->ss_flags & SS_ACTIVE) == 0)
1010 return;
1011
1012 font = si->si_font;
1013 pb = (*si->si_pbuf_get)(si);
1014
1015 /*
1016 * Create a mask from the glyph. Squeeze the foreground color
1017 * through the mask, and then squeeze the background color through
1018 * the inverted mask. We may well read outside the glyph when
1019 * creating the mask, but it's bounded by the hardware so it
1020 * shouldn't matter a great deal...
1021 */
1022 pb[0] = STAMP_CMD_LINES | STAMP_RGB_FLAT | STAMP_XY_PERPRIMATIVE |
1023 STAMP_LW_PERPRIMATIVE;
1024 pb[1] = font->fontheight > 16 ? 0x04ffffff : 0x02ffffff;
1025 pb[2] = 0x0;
1026 pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY;
1027
1028 r *= font->fontheight;
1029 c *= font->fontwidth;
1030 uc = (uc - font->firstchar) * font->stride * font->fontheight;
1031 fr = (u_short *)((caddr_t)font->data + uc);
1032 bgcolor = DUPBYTE0((attr & 0xf0) >> 4);
1033 fgcolor = DUPBYTE0(attr & 0x0f);
1034
1035 i = ((font->fontheight > 16 ? 16 : font->fontheight) << 2) - 1;
1036 v1 = (c << 19) | ((r << 3) + i);
1037 v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
1038 xya = XYMASKADDR(si->si_stampw, si->si_stamph, c, r, 0, 0);
1039
1040 pb[4] = PACK(fr, 0);
1041 pb[5] = PACK(fr, 2);
1042 pb[6] = PACK(fr, 4);
1043 pb[7] = PACK(fr, 6);
1044 pb[8] = PACK(fr, 8);
1045 pb[9] = PACK(fr, 10);
1046 pb[10] = PACK(fr, 12);
1047 pb[11] = PACK(fr, 14);
1048 pb[12] = xya;
1049 pb[13] = v1;
1050 pb[14] = v2;
1051 pb[15] = i;
1052 pb[16] = fgcolor;
1053
1054 pb[17] = ~pb[4];
1055 pb[18] = ~pb[5];
1056 pb[19] = ~pb[6];
1057 pb[20] = ~pb[7];
1058 pb[21] = ~pb[8];
1059 pb[22] = ~pb[9];
1060 pb[23] = ~pb[10];
1061 pb[24] = ~pb[11];
1062 pb[25] = xya;
1063 pb[26] = v1;
1064 pb[27] = v2;
1065 pb[28] = i;
1066 pb[29] = bgcolor;
1067
1068 /* Two more squeezes for the lower part of the character. */
1069 if (font->fontheight > 16) {
1070 i = ((font->fontheight - 16) << 2) - 1;
1071 r += 16;
1072 v1 = (c << 19) | ((r << 3) + i);
1073 v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
1074
1075 pb[30] = PACK(fr, 16);
1076 pb[31] = PACK(fr, 18);
1077 pb[32] = PACK(fr, 20);
1078 pb[33] = PACK(fr, 22);
1079 pb[34] = PACK(fr, 24);
1080 pb[35] = PACK(fr, 26);
1081 pb[36] = PACK(fr, 28);
1082 pb[37] = PACK(fr, 30);
1083 pb[38] = xya;
1084 pb[39] = v1;
1085 pb[40] = v2;
1086 pb[41] = i;
1087 pb[42] = fgcolor;
1088
1089 pb[43] = ~pb[30];
1090 pb[44] = ~pb[31];
1091 pb[45] = ~pb[32];
1092 pb[46] = ~pb[33];
1093 pb[47] = ~pb[34];
1094 pb[48] = ~pb[35];
1095 pb[49] = ~pb[36];
1096 pb[50] = ~pb[37];
1097 pb[51] = xya;
1098 pb[52] = v1;
1099 pb[53] = v2;
1100 pb[54] = i;
1101 pb[55] = bgcolor;
1102 }
1103
1104 (*si->si_pbuf_post)(si, pb);
1105 }
1106
1107 int
1108 stic_mapchar(void *cookie, int c, u_int *cp)
1109 {
1110 struct stic_info *si;
1111
1112 si = ((struct stic_screen *)cookie)->ss_si;
1113
1114 if (c < si->si_font->firstchar || c == ' ') {
1115 *cp = 0;
1116 return (0);
1117 }
1118
1119 if (c - si->si_font->firstchar >= si->si_font->numchars) {
1120 *cp = 0;
1121 return (0);
1122 }
1123
1124 *cp = c;
1125 return (5);
1126 }
1127
1128 void
1129 stic_cursor(void *cookie, int on, int row, int col)
1130 {
1131 struct stic_screen *ss;
1132 struct stic_info *si;
1133 int s;
1134
1135 ss = cookie;
1136 si = ss->ss_si;
1137
1138 ss->ss_curx = col * si->si_fontw;
1139 ss->ss_cury = row * si->si_fonth;
1140
1141 s = spltty();
1142
1143 if (on)
1144 ss->ss_flags |= SS_CURENB;
1145 else
1146 ss->ss_flags &= ~SS_CURENB;
1147
1148 if ((ss->ss_flags & SS_ACTIVE) != 0) {
1149 si->si_cursor.cc_pos.x = ss->ss_curx;
1150 si->si_cursor.cc_pos.y = ss->ss_cury;
1151 si->si_flags |= SI_CURENB_CHANGED;
1152 stic_set_hwcurpos(si);
1153
1154 /*
1155 * XXX Since we don't yet receive vblank interrupts from the
1156 * PXG, we must flush immediatley.
1157 */
1158 if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1159 stic_flush(si);
1160 }
1161
1162 splx(s);
1163 }
1164
1165 void
1166 stic_flush(struct stic_info *si)
1167 {
1168 volatile u_int32_t *vdac;
1169 int v;
1170
1171 if ((si->si_flags & SI_ALL_CHANGED) == 0)
1172 return;
1173
1174 vdac = si->si_vdac;
1175 v = si->si_flags;
1176 si->si_flags &= ~SI_ALL_CHANGED;
1177
1178 if ((v & SI_CURENB_CHANGED) != 0) {
1179 SELECT(vdac, BT459_IREG_CCR);
1180 if ((si->si_curscreen->ss_flags & SS_CURENB) != 0)
1181 REG(vdac, bt_reg) = 0x00c0c0c0;
1182 else
1183 REG(vdac, bt_reg) = 0x00000000;
1184 tc_wmb();
1185 }
1186
1187 if ((v & SI_CURCMAP_CHANGED) != 0) {
1188 u_int8_t *cp;
1189
1190 cp = si->si_cursor.cc_color;
1191
1192 SELECT(vdac, BT459_IREG_CCOLOR_2);
1193 REG(vdac, bt_reg) = DUPBYTE0(cp[1]); tc_wmb();
1194 REG(vdac, bt_reg) = DUPBYTE0(cp[3]); tc_wmb();
1195 REG(vdac, bt_reg) = DUPBYTE0(cp[5]); tc_wmb();
1196 REG(vdac, bt_reg) = DUPBYTE0(cp[0]); tc_wmb();
1197 REG(vdac, bt_reg) = DUPBYTE0(cp[2]); tc_wmb();
1198 REG(vdac, bt_reg) = DUPBYTE0(cp[4]); tc_wmb();
1199 }
1200
1201 if ((v & SI_CURSHAPE_CHANGED) != 0) {
1202 u_int8_t *ip, *mp, img, msk;
1203 u_int8_t u;
1204 int bcnt;
1205
1206 ip = (u_int8_t *)si->si_cursor.cc_image;
1207 mp = (u_int8_t *)(si->si_cursor.cc_image + CURSOR_MAX_SIZE);
1208
1209 bcnt = 0;
1210 SELECT(vdac, BT459_IREG_CRAM_BASE);
1211 /* 64 pixel scan line is consisted with 16 byte cursor ram */
1212 while (bcnt < CURSOR_MAX_SIZE * 16) {
1213 img = *ip++;
1214 msk = *mp++;
1215 img &= msk; /* cookie off image */
1216 u = (msk & 0x0f) << 4 | (img & 0x0f);
1217 REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
1218 tc_wmb();
1219 u = (msk & 0xf0) | (img & 0xf0) >> 4;
1220 REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
1221 tc_wmb();
1222 bcnt += 2;
1223 }
1224 }
1225
1226 if ((v & SI_CMAP_CHANGED) != 0) {
1227 struct stic_hwcmap256 *cm;
1228 int index;
1229
1230 cm = &si->si_cmap;
1231
1232 SELECT(vdac, 0);
1233 SELECT(vdac, 0);
1234 for (index = 0; index < CMAP_SIZE; index++) {
1235 REG(vdac, bt_cmap) = DUPBYTE0(cm->r[index]);
1236 tc_wmb();
1237 REG(vdac, bt_cmap) = DUPBYTE0(cm->g[index]);
1238 tc_wmb();
1239 REG(vdac, bt_cmap) = DUPBYTE0(cm->b[index]);
1240 tc_wmb();
1241 }
1242 }
1243 }
1244
1245 int
1246 stic_get_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
1247 {
1248 u_int index, count;
1249
1250 index = p->index;
1251 count = p->count;
1252
1253 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
1254 return (EINVAL);
1255
1256 if (!uvm_useracc(p->red, count, B_WRITE) ||
1257 !uvm_useracc(p->green, count, B_WRITE) ||
1258 !uvm_useracc(p->blue, count, B_WRITE))
1259 return (EFAULT);
1260
1261 copyout(&si->si_cmap.r[index], p->red, count);
1262 copyout(&si->si_cmap.g[index], p->green, count);
1263 copyout(&si->si_cmap.b[index], p->blue, count);
1264 return (0);
1265 }
1266
1267 int
1268 stic_set_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
1269 {
1270 u_int index, count;
1271 int s;
1272
1273 index = p->index;
1274 count = p->count;
1275
1276 if ((index + count) > CMAP_SIZE)
1277 return (EINVAL);
1278
1279 if (!uvm_useracc(p->red, count, B_READ) ||
1280 !uvm_useracc(p->green, count, B_READ) ||
1281 !uvm_useracc(p->blue, count, B_READ))
1282 return (EFAULT);
1283
1284 s = spltty();
1285 copyin(p->red, &si->si_cmap.r[index], count);
1286 copyin(p->green, &si->si_cmap.g[index], count);
1287 copyin(p->blue, &si->si_cmap.b[index], count);
1288 si->si_flags |= SI_CMAP_CHANGED;
1289 splx(s);
1290
1291 /*
1292 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1293 * must flush immediatley.
1294 */
1295 if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1296 stic_flush(si);
1297
1298 return (0);
1299 }
1300
1301 int
1302 stic_set_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1303 {
1304 #define cc (&si->si_cursor)
1305 u_int v, index, count, icount;
1306 struct stic_screen *ss;
1307 int s;
1308
1309 v = p->which;
1310 ss = si->si_curscreen;
1311
1312 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
1313 index = p->cmap.index;
1314 count = p->cmap.count;
1315 if (index >= 2 || (index + count) > 2)
1316 return (EINVAL);
1317 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
1318 !uvm_useracc(p->cmap.green, count, B_READ) ||
1319 !uvm_useracc(p->cmap.blue, count, B_READ))
1320 return (EFAULT);
1321 }
1322
1323 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
1324 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
1325 return (EINVAL);
1326 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
1327 if (!uvm_useracc(p->image, icount, B_READ) ||
1328 !uvm_useracc(p->mask, icount, B_READ))
1329 return (EFAULT);
1330 }
1331
1332 if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) != 0) {
1333 if (v & WSDISPLAY_CURSOR_DOCUR)
1334 cc->cc_hot = p->hot;
1335 if (v & WSDISPLAY_CURSOR_DOPOS)
1336 stic_set_curpos(si, &p->pos);
1337 }
1338
1339 s = spltty();
1340
1341 if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) {
1342 if (p->enable)
1343 ss->ss_flags |= SS_CURENB;
1344 else
1345 ss->ss_flags &= ~SS_CURENB;
1346 si->si_flags |= SI_CURENB_CHANGED;
1347 }
1348
1349 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
1350 copyin(p->cmap.red, &cc->cc_color[index], count);
1351 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
1352 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
1353 si->si_flags |= SI_CURCMAP_CHANGED;
1354 }
1355
1356 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
1357 memset(cc->cc_image, 0, sizeof(cc->cc_image));
1358 copyin(p->image, cc->cc_image, icount);
1359 copyin(p->mask, cc->cc_image + CURSOR_MAX_SIZE, icount);
1360 si->si_flags |= SI_CURSHAPE_CHANGED;
1361 }
1362
1363 splx(s);
1364
1365 /*
1366 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1367 * must flush immediatley.
1368 */
1369 if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1370 stic_flush(si);
1371
1372 return (0);
1373 #undef cc
1374 }
1375
1376 int
1377 stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1378 {
1379
1380 /* XXX */
1381 return (ENOTTY);
1382 }
1383
1384 void
1385 stic_set_curpos(struct stic_info *si, struct wsdisplay_curpos *curpos)
1386 {
1387 int x, y;
1388
1389 x = curpos->x;
1390 y = curpos->y;
1391
1392 if (y < 0)
1393 y = 0;
1394 else if (y > 1023)
1395 y = 1023;
1396 if (x < 0)
1397 x = 0;
1398 else if (x > 1279)
1399 x = 1279;
1400
1401 si->si_cursor.cc_pos.x = x;
1402 si->si_cursor.cc_pos.y = y;
1403 stic_set_hwcurpos(si);
1404 }
1405
1406 void
1407 stic_set_hwcurpos(struct stic_info *si)
1408 {
1409 volatile u_int32_t *vdac;
1410 int x, y, s;
1411
1412 vdac = si->si_vdac;
1413
1414 x = si->si_cursor.cc_pos.x - si->si_cursor.cc_hot.x;
1415 y = si->si_cursor.cc_pos.y - si->si_cursor.cc_hot.y;
1416 x += STIC_MAGIC_X;
1417 y += STIC_MAGIC_Y;
1418
1419 s = spltty();
1420 SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
1421 REG(vdac, bt_reg) = DUPBYTE0(x); tc_wmb();
1422 REG(vdac, bt_reg) = DUPBYTE1(x); tc_wmb();
1423 REG(vdac, bt_reg) = DUPBYTE0(y); tc_wmb();
1424 REG(vdac, bt_reg) = DUPBYTE1(y); tc_wmb();
1425 splx(s);
1426 }
1427
1428 /*
1429 * STIC control inteface. We have a separate device for mapping the board,
1430 * because access to the DMA engine means that it's possible to circumvent
1431 * the securelevel mechanism. Given the way devices work in the BSD kernel,
1432 * and given the unfortunate design of the mmap() call it's near impossible
1433 * to protect against this using a shared device (i.e. wsdisplay).
1434 *
1435 * This is a gross hack... Hopefully not too many other devices will need
1436 * it.
1437 */
1438 int
1439 sticopen(dev_t dev, int flag, int mode, struct proc *p)
1440 {
1441 struct stic_info *si;
1442 int s;
1443
1444 if (securelevel > 0)
1445 return (EPERM);
1446 if (minor(dev) >= STIC_MAXDV)
1447 return (ENXIO);
1448 if ((si = stic_info[minor(dev)]) == NULL)
1449 return (ENXIO);
1450
1451 s = spltty();
1452 if ((si->si_flags & SI_DVOPEN) != 0) {
1453 splx(s);
1454 return (EBUSY);
1455 }
1456 si->si_flags |= SI_DVOPEN;
1457 splx(s);
1458
1459 return (0);
1460 }
1461
1462 int
1463 sticclose(dev_t dev, int flag, int mode, struct proc *p)
1464 {
1465 struct stic_info *si;
1466 int s;
1467
1468 si = stic_info[minor(dev)];
1469 s = spltty();
1470 si->si_flags &= ~SI_DVOPEN;
1471 splx(s);
1472
1473 return (0);
1474 }
1475
1476 paddr_t
1477 sticmmap(dev_t dev, off_t offset, int prot)
1478 {
1479 struct stic_info *si;
1480 struct stic_xmap *sxm;
1481 paddr_t pa;
1482
1483 si = stic_info[minor(dev)];
1484 sxm = NULL;
1485
1486 if (securelevel > 0)
1487 return (-1L);
1488 if (si->si_dispmode != WSDISPLAYIO_MODE_MAPPED)
1489 return (-1L);
1490
1491 if (offset < 0)
1492 return ((paddr_t)-1L);
1493
1494 if (offset < sizeof(sxm->sxm_stic)) {
1495 pa = STIC_KSEG_TO_PHYS(si->si_stic);
1496 return (machine_btop(pa + offset));
1497 }
1498 offset -= sizeof(sxm->sxm_stic);
1499
1500 if (offset < sizeof(sxm->sxm_poll)) {
1501 pa = STIC_KSEG_TO_PHYS(si->si_slotbase);
1502 return (machine_btop(pa + offset));
1503 }
1504 offset -= sizeof(sxm->sxm_poll);
1505
1506 if (offset < si->si_buf_size)
1507 return (machine_btop(si->si_buf_phys + offset));
1508
1509 return ((paddr_t)-1L);
1510 }
1511