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