stic.c revision 1.12 1 /* $NetBSD: stic.c,v 1.12 2001/11/13 06:26:10 lukem 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.12 2001/11/13 06:26:10 lukem 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);
637 memset(ss->ss_backing, 0, size);
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);
653 memset(ss, 0, sizeof(*ss));
654 }
655 stic_setup_backing(si, ss);
656
657 ss->ss_si = si;
658 ss->ss_flags = SS_ALLOCED | SS_CURENB;
659
660 *cookiep = ss;
661 *curxp = 0;
662 *curyp = 0;
663
664 stic_alloc_attr(ss, 0, 0, 0, attrp);
665 return (0);
666 }
667
668 void
669 stic_free_screen(void *v, void *cookie)
670 {
671 struct stic_screen *ss;
672
673 ss = cookie;
674
675 #ifdef DIAGNOSTIC
676 if (ss == &stic_consscr)
677 panic("stic_free_screen: console");
678 if (ss == ((struct stic_info *)v)->si_curscreen)
679 panic("stic_free_screen: freeing current screen");
680 #endif
681
682 free(ss->ss_backing, M_DEVBUF);
683 free(ss, M_DEVBUF);
684 }
685
686 int
687 stic_show_screen(void *v, void *cookie, int waitok,
688 void (*cb)(void *, int, int), void *cbarg)
689 {
690 struct stic_info *si;
691
692 si = (struct stic_info *)v;
693 if (si->si_switchcbarg != NULL)
694 return (EAGAIN);
695 si->si_switchcb = cb;
696 si->si_switchcbarg = cbarg;
697
698 if (cb != NULL) {
699 callout_reset(&si->si_switch_callout, 0, stic_do_switch,
700 cookie);
701 return (EAGAIN);
702 }
703
704 stic_do_switch(cookie);
705 return (0);
706 }
707
708 void
709 stic_do_switch(void *cookie)
710 {
711 struct stic_screen *ss;
712 struct stic_info *si;
713 u_int r, c, nr, nc;
714 u_int16_t *p, *sp;
715
716 ss = cookie;
717 si = ss->ss_si;
718
719 #ifdef DIAGNOSTIC
720 if (ss->ss_backing == NULL)
721 panic("stic_do_switch: screen not backed");
722 #endif
723
724 /* Swap in the new screen, and temporarily disable its backing. */
725 if (si->si_curscreen != NULL)
726 si->si_curscreen->ss_flags ^= SS_ACTIVE;
727 si->si_curscreen = ss;
728 ss->ss_flags |= SS_ACTIVE;
729 sp = ss->ss_backing;
730 ss->ss_backing = NULL;
731
732 /*
733 * We assume that most of the screen is blank and blast it with
734 * eraserows(), because eraserows() is cheap.
735 */
736 nr = si->si_consh;
737 stic_eraserows(ss, 0, nr, 0);
738
739 nc = si->si_consw;
740 p = sp;
741 for (r = 0; r < nr; r++)
742 for (c = 0; c < nc; c += 2, p += 2) {
743 if ((p[0] & 0xfff0) != 0)
744 stic_putchar(ss, r, c, p[0] >> 8,
745 p[0] & 0x00ff);
746 if ((p[1] & 0xfff0) != 0)
747 stic_putchar(ss, r, c + 1, p[1] >> 8,
748 p[1] & 0x00ff);
749 }
750
751 /*
752 * Re-enable the screen's backing, and move the cursor to the
753 * correct spot.
754 */
755 ss->ss_backing = sp;
756 si->si_cursor.cc_pos.x = ss->ss_curx;
757 si->si_cursor.cc_pos.y = ss->ss_cury;
758 stic_set_hwcurpos(si);
759 si->si_flags |= SI_CURENB_CHANGED;
760
761 /*
762 * XXX Since we don't yet receive vblank interrupts from the
763 * PXG, we must flush immediatley.
764 */
765 if (si->si_disptype == WSDISPLAY_TYPE_PXG)
766 stic_flush(si);
767
768 /* Tell wscons that we're done. */
769 if (si->si_switchcbarg != NULL) {
770 cookie = si->si_switchcbarg;
771 si->si_switchcbarg = NULL;
772 (*si->si_switchcb)(cookie, 0, 0);
773 }
774 }
775
776 int
777 stic_alloc_attr(void *cookie, int fg, int bg, int flags, long *attr)
778 {
779 long tmp;
780
781 if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0)
782 return (EINVAL);
783
784 if ((flags & WSATTR_WSCOLORS) == 0) {
785 fg = 7;
786 bg = 0;
787 }
788
789 if ((flags & WSATTR_HILIT) != 0)
790 fg += 8;
791
792 tmp = fg | (bg << 4);
793 *attr = tmp | (tmp << 16);
794 return (0);
795 }
796
797 void
798 stic_erasecols(void *cookie, int row, int col, int num, long attr)
799 {
800 struct stic_info *si;
801 struct stic_screen *ss;
802 u_int32_t *pb;
803 u_int i, linewidth;
804 u_int16_t *p;
805
806 ss = cookie;
807 si = ss->ss_si;
808
809 if (ss->ss_backing != NULL) {
810 p = ss->ss_backing + row * si->si_consw + col;
811 for (i = num; i != 0; i--)
812 *p++ = (u_int16_t)attr;
813 }
814 if ((ss->ss_flags & SS_ACTIVE) == 0)
815 return;
816
817 col = (col * si->si_fontw) << 19;
818 num = (num * si->si_fontw) << 19;
819 row = row * si->si_fonth;
820 attr = (attr & 0xf0) >> 4;
821 linewidth = (si->si_fonth << 2) - 1;
822 row = (row << 3) + linewidth;
823
824 pb = (*si->si_pbuf_get)(si);
825
826 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
827 pb[1] = 0x01ffffff;
828 pb[2] = 0;
829 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
830 pb[4] = linewidth;
831 pb[5] = DUPBYTE0(attr);
832 pb[6] = col | row;
833 pb[7] = (col + num) | row;
834
835 (*si->si_pbuf_post)(si, pb);
836 }
837
838 void
839 stic_eraserows(void *cookie, int row, int num, long attr)
840 {
841 struct stic_info *si;
842 struct stic_screen *ss;
843 u_int linewidth, i;
844 u_int32_t *pb;
845
846 ss = cookie;
847 si = ss->ss_si;
848
849 if (ss->ss_backing != NULL) {
850 pb = (u_int32_t *)(ss->ss_backing + row * si->si_consw);
851 for (i = si->si_consw * num; i > 0; i -= 2)
852 *pb++ = (u_int32_t)attr;
853 }
854 if ((ss->ss_flags & SS_ACTIVE) == 0)
855 return;
856
857 row *= si->si_fonth;
858 num *= si->si_fonth;
859 attr = (attr & 0xf0) >> 4;
860 linewidth = (num << 2) - 1;
861 row = (row << 3) + linewidth;
862
863 pb = (*si->si_pbuf_get)(si);
864
865 pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
866 pb[1] = 0x01ffffff;
867 pb[2] = 0;
868 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
869 pb[4] = linewidth;
870 pb[5] = DUPBYTE0(attr);
871 pb[6] = row;
872 pb[7] = (1280 << 19) | row;
873
874 (*si->si_pbuf_post)(si, pb);
875 }
876
877 void
878 stic_copyrows(void *cookie, int src, int dst, int height)
879 {
880 struct stic_info *si;
881 struct stic_screen *ss;
882 u_int32_t *pb, *pbs;
883 u_int num, inc, adj;
884
885 ss = cookie;
886 si = ss->ss_si;
887
888 if (ss->ss_backing != NULL)
889 bcopy(ss->ss_backing + src * si->si_consw,
890 ss->ss_backing + dst * si->si_consw,
891 si->si_consw * sizeof(*ss->ss_backing) * height);
892 if ((ss->ss_flags & SS_ACTIVE) == 0)
893 return;
894
895 /*
896 * We need to do this in reverse if the destination row is below
897 * the source.
898 */
899 if (dst > src) {
900 src += height;
901 dst += height;
902 inc = -8;
903 adj = -1;
904 } else {
905 inc = 8;
906 adj = 0;
907 }
908
909 src = (src * si->si_fonth + adj) << 3;
910 dst = (dst * si->si_fonth + adj) << 3;
911 height *= si->si_fonth;
912
913 while (height > 0) {
914 num = (height < 255 ? height : 255);
915 height -= num;
916
917 pbs = (*si->si_pbuf_get)(si);
918 pb = pbs;
919
920 pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
921 pb[1] = (num << 24) | 0xffffff;
922 pb[2] = 0x0;
923 pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN |
924 STAMP_COPYSPAN_ALIGNED;
925 pb[4] = 1; /* linewidth */
926
927 for (; num != 0; num--, src += inc, dst += inc, pb += 3) {
928 pb[5] = 1280 << 3;
929 pb[6] = src;
930 pb[7] = dst;
931 }
932
933 (*si->si_pbuf_post)(si, pbs);
934 }
935 }
936
937 void
938 stic_copycols(void *cookie, int row, int src, int dst, int num)
939 {
940 struct stic_info *si;
941 struct stic_screen *ss;
942 u_int height, updword;
943 u_int32_t *pb, *pbs;
944
945 ss = cookie;
946 si = ss->ss_si;
947
948 if (ss->ss_backing != NULL)
949 bcopy(ss->ss_backing + row * si->si_consw + src,
950 ss->ss_backing + row * si->si_consw + dst,
951 num * sizeof(*ss->ss_backing));
952 if ((ss->ss_flags & SS_ACTIVE) == 0)
953 return;
954
955 /*
956 * The stamp reads and writes left -> right only, so we need to
957 * buffer the span if the source and destination regions overlap
958 * and the source is left of the destination.
959 */
960 updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN;
961
962 if (src < dst && src + num > dst)
963 updword |= STAMP_HALF_BUFF;
964
965 row = (row * si->si_fonth) << 3;
966 num = (num * si->si_fontw) << 3;
967 src = row | ((src * si->si_fontw) << 19);
968 dst = row | ((dst * si->si_fontw) << 19);
969 height = si->si_fonth;
970
971 pbs = (*si->si_pbuf_get)(si);
972 pb = pbs;
973
974 pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
975 pb[1] = (height << 24) | 0xffffff;
976 pb[2] = 0x0;
977 pb[3] = updword;
978 pb[4] = 1; /* linewidth */
979
980 for ( ; height != 0; height--, src += 8, dst += 8, pb += 3) {
981 pb[5] = num;
982 pb[6] = src;
983 pb[7] = dst;
984 }
985
986 (*si->si_pbuf_post)(si, pbs);
987 }
988
989 void
990 stic_putchar(void *cookie, int r, int c, u_int uc, long attr)
991 {
992 struct wsdisplay_font *font;
993 struct stic_screen *ss;
994 struct stic_info *si;
995 u_int i, bgcolor, fgcolor;
996 u_int *pb, v1, v2, xya;
997 u_short *fr;
998
999 ss = cookie;
1000 si = ss->ss_si;
1001
1002 /* It's cheaper to use erasecols() to blit blanks. */
1003 if (uc == 0) {
1004 stic_erasecols(cookie, r, c, 1, attr);
1005 return;
1006 }
1007
1008 if (ss->ss_backing != NULL)
1009 ss->ss_backing[r * si->si_consw + c] =
1010 (u_short)((attr & 0xff) | (uc << 8));
1011 if ((ss->ss_flags & SS_ACTIVE) == 0)
1012 return;
1013
1014 font = si->si_font;
1015 pb = (*si->si_pbuf_get)(si);
1016
1017 /*
1018 * Create a mask from the glyph. Squeeze the foreground color
1019 * through the mask, and then squeeze the background color through
1020 * the inverted mask. We may well read outside the glyph when
1021 * creating the mask, but it's bounded by the hardware so it
1022 * shouldn't matter a great deal...
1023 */
1024 pb[0] = STAMP_CMD_LINES | STAMP_RGB_FLAT | STAMP_XY_PERPRIMATIVE |
1025 STAMP_LW_PERPRIMATIVE;
1026 pb[1] = font->fontheight > 16 ? 0x04ffffff : 0x02ffffff;
1027 pb[2] = 0x0;
1028 pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY;
1029
1030 r *= font->fontheight;
1031 c *= font->fontwidth;
1032 uc = (uc - font->firstchar) * font->stride * font->fontheight;
1033 fr = (u_short *)((caddr_t)font->data + uc);
1034 bgcolor = DUPBYTE0((attr & 0xf0) >> 4);
1035 fgcolor = DUPBYTE0(attr & 0x0f);
1036
1037 i = ((font->fontheight > 16 ? 16 : font->fontheight) << 2) - 1;
1038 v1 = (c << 19) | ((r << 3) + i);
1039 v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
1040 xya = XYMASKADDR(si->si_stampw, si->si_stamph, c, r, 0, 0);
1041
1042 pb[4] = PACK(fr, 0);
1043 pb[5] = PACK(fr, 2);
1044 pb[6] = PACK(fr, 4);
1045 pb[7] = PACK(fr, 6);
1046 pb[8] = PACK(fr, 8);
1047 pb[9] = PACK(fr, 10);
1048 pb[10] = PACK(fr, 12);
1049 pb[11] = PACK(fr, 14);
1050 pb[12] = xya;
1051 pb[13] = v1;
1052 pb[14] = v2;
1053 pb[15] = i;
1054 pb[16] = fgcolor;
1055
1056 pb[17] = ~pb[4];
1057 pb[18] = ~pb[5];
1058 pb[19] = ~pb[6];
1059 pb[20] = ~pb[7];
1060 pb[21] = ~pb[8];
1061 pb[22] = ~pb[9];
1062 pb[23] = ~pb[10];
1063 pb[24] = ~pb[11];
1064 pb[25] = xya;
1065 pb[26] = v1;
1066 pb[27] = v2;
1067 pb[28] = i;
1068 pb[29] = bgcolor;
1069
1070 /* Two more squeezes for the lower part of the character. */
1071 if (font->fontheight > 16) {
1072 i = ((font->fontheight - 16) << 2) - 1;
1073 r += 16;
1074 v1 = (c << 19) | ((r << 3) + i);
1075 v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
1076
1077 pb[30] = PACK(fr, 16);
1078 pb[31] = PACK(fr, 18);
1079 pb[32] = PACK(fr, 20);
1080 pb[33] = PACK(fr, 22);
1081 pb[34] = PACK(fr, 24);
1082 pb[35] = PACK(fr, 26);
1083 pb[36] = PACK(fr, 28);
1084 pb[37] = PACK(fr, 30);
1085 pb[38] = xya;
1086 pb[39] = v1;
1087 pb[40] = v2;
1088 pb[41] = i;
1089 pb[42] = fgcolor;
1090
1091 pb[43] = ~pb[30];
1092 pb[44] = ~pb[31];
1093 pb[45] = ~pb[32];
1094 pb[46] = ~pb[33];
1095 pb[47] = ~pb[34];
1096 pb[48] = ~pb[35];
1097 pb[49] = ~pb[36];
1098 pb[50] = ~pb[37];
1099 pb[51] = xya;
1100 pb[52] = v1;
1101 pb[53] = v2;
1102 pb[54] = i;
1103 pb[55] = bgcolor;
1104 }
1105
1106 (*si->si_pbuf_post)(si, pb);
1107 }
1108
1109 int
1110 stic_mapchar(void *cookie, int c, u_int *cp)
1111 {
1112 struct stic_info *si;
1113
1114 si = ((struct stic_screen *)cookie)->ss_si;
1115
1116 if (c < si->si_font->firstchar || c == ' ') {
1117 *cp = 0;
1118 return (0);
1119 }
1120
1121 if (c - si->si_font->firstchar >= si->si_font->numchars) {
1122 *cp = 0;
1123 return (0);
1124 }
1125
1126 *cp = c;
1127 return (5);
1128 }
1129
1130 void
1131 stic_cursor(void *cookie, int on, int row, int col)
1132 {
1133 struct stic_screen *ss;
1134 struct stic_info *si;
1135 int s;
1136
1137 ss = cookie;
1138 si = ss->ss_si;
1139
1140 ss->ss_curx = col * si->si_fontw;
1141 ss->ss_cury = row * si->si_fonth;
1142
1143 s = spltty();
1144
1145 if (on)
1146 ss->ss_flags |= SS_CURENB;
1147 else
1148 ss->ss_flags &= ~SS_CURENB;
1149
1150 if ((ss->ss_flags & SS_ACTIVE) != 0) {
1151 si->si_cursor.cc_pos.x = ss->ss_curx;
1152 si->si_cursor.cc_pos.y = ss->ss_cury;
1153 si->si_flags |= SI_CURENB_CHANGED;
1154 stic_set_hwcurpos(si);
1155
1156 /*
1157 * XXX Since we don't yet receive vblank interrupts from the
1158 * PXG, we must flush immediatley.
1159 */
1160 if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1161 stic_flush(si);
1162 }
1163
1164 splx(s);
1165 }
1166
1167 void
1168 stic_flush(struct stic_info *si)
1169 {
1170 volatile u_int32_t *vdac;
1171 int v;
1172
1173 if ((si->si_flags & SI_ALL_CHANGED) == 0)
1174 return;
1175
1176 vdac = si->si_vdac;
1177 v = si->si_flags;
1178 si->si_flags &= ~SI_ALL_CHANGED;
1179
1180 if ((v & SI_CURENB_CHANGED) != 0) {
1181 SELECT(vdac, BT459_IREG_CCR);
1182 if ((si->si_curscreen->ss_flags & SS_CURENB) != 0)
1183 REG(vdac, bt_reg) = 0x00c0c0c0;
1184 else
1185 REG(vdac, bt_reg) = 0x00000000;
1186 tc_wmb();
1187 }
1188
1189 if ((v & SI_CURCMAP_CHANGED) != 0) {
1190 u_int8_t *cp;
1191
1192 cp = si->si_cursor.cc_color;
1193
1194 SELECT(vdac, BT459_IREG_CCOLOR_2);
1195 REG(vdac, bt_reg) = DUPBYTE0(cp[1]); tc_wmb();
1196 REG(vdac, bt_reg) = DUPBYTE0(cp[3]); tc_wmb();
1197 REG(vdac, bt_reg) = DUPBYTE0(cp[5]); tc_wmb();
1198 REG(vdac, bt_reg) = DUPBYTE0(cp[0]); tc_wmb();
1199 REG(vdac, bt_reg) = DUPBYTE0(cp[2]); tc_wmb();
1200 REG(vdac, bt_reg) = DUPBYTE0(cp[4]); tc_wmb();
1201 }
1202
1203 if ((v & SI_CURSHAPE_CHANGED) != 0) {
1204 u_int8_t *ip, *mp, img, msk;
1205 u_int8_t u;
1206 int bcnt;
1207
1208 ip = (u_int8_t *)si->si_cursor.cc_image;
1209 mp = (u_int8_t *)(si->si_cursor.cc_image + CURSOR_MAX_SIZE);
1210
1211 bcnt = 0;
1212 SELECT(vdac, BT459_IREG_CRAM_BASE);
1213 /* 64 pixel scan line is consisted with 16 byte cursor ram */
1214 while (bcnt < CURSOR_MAX_SIZE * 16) {
1215 img = *ip++;
1216 msk = *mp++;
1217 img &= msk; /* cookie off image */
1218 u = (msk & 0x0f) << 4 | (img & 0x0f);
1219 REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
1220 tc_wmb();
1221 u = (msk & 0xf0) | (img & 0xf0) >> 4;
1222 REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
1223 tc_wmb();
1224 bcnt += 2;
1225 }
1226 }
1227
1228 if ((v & SI_CMAP_CHANGED) != 0) {
1229 struct stic_hwcmap256 *cm;
1230 int index;
1231
1232 cm = &si->si_cmap;
1233
1234 SELECT(vdac, 0);
1235 SELECT(vdac, 0);
1236 for (index = 0; index < CMAP_SIZE; index++) {
1237 REG(vdac, bt_cmap) = DUPBYTE0(cm->r[index]);
1238 tc_wmb();
1239 REG(vdac, bt_cmap) = DUPBYTE0(cm->g[index]);
1240 tc_wmb();
1241 REG(vdac, bt_cmap) = DUPBYTE0(cm->b[index]);
1242 tc_wmb();
1243 }
1244 }
1245 }
1246
1247 int
1248 stic_get_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
1249 {
1250 u_int index, count;
1251
1252 index = p->index;
1253 count = p->count;
1254
1255 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
1256 return (EINVAL);
1257
1258 if (!uvm_useracc(p->red, count, B_WRITE) ||
1259 !uvm_useracc(p->green, count, B_WRITE) ||
1260 !uvm_useracc(p->blue, count, B_WRITE))
1261 return (EFAULT);
1262
1263 copyout(&si->si_cmap.r[index], p->red, count);
1264 copyout(&si->si_cmap.g[index], p->green, count);
1265 copyout(&si->si_cmap.b[index], p->blue, count);
1266 return (0);
1267 }
1268
1269 int
1270 stic_set_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
1271 {
1272 u_int index, count;
1273 int s;
1274
1275 index = p->index;
1276 count = p->count;
1277
1278 if ((index + count) > CMAP_SIZE)
1279 return (EINVAL);
1280
1281 if (!uvm_useracc(p->red, count, B_READ) ||
1282 !uvm_useracc(p->green, count, B_READ) ||
1283 !uvm_useracc(p->blue, count, B_READ))
1284 return (EFAULT);
1285
1286 s = spltty();
1287 copyin(p->red, &si->si_cmap.r[index], count);
1288 copyin(p->green, &si->si_cmap.g[index], count);
1289 copyin(p->blue, &si->si_cmap.b[index], count);
1290 si->si_flags |= SI_CMAP_CHANGED;
1291 splx(s);
1292
1293 /*
1294 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1295 * must flush immediatley.
1296 */
1297 if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1298 stic_flush(si);
1299
1300 return (0);
1301 }
1302
1303 int
1304 stic_set_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1305 {
1306 #define cc (&si->si_cursor)
1307 u_int v, index, count, icount;
1308 struct stic_screen *ss;
1309 int s;
1310
1311 v = p->which;
1312 ss = si->si_curscreen;
1313
1314 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
1315 index = p->cmap.index;
1316 count = p->cmap.count;
1317 if (index >= 2 || (index + count) > 2)
1318 return (EINVAL);
1319 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
1320 !uvm_useracc(p->cmap.green, count, B_READ) ||
1321 !uvm_useracc(p->cmap.blue, count, B_READ))
1322 return (EFAULT);
1323 }
1324
1325 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
1326 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
1327 return (EINVAL);
1328 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
1329 if (!uvm_useracc(p->image, icount, B_READ) ||
1330 !uvm_useracc(p->mask, icount, B_READ))
1331 return (EFAULT);
1332 }
1333
1334 if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) != 0) {
1335 if (v & WSDISPLAY_CURSOR_DOCUR)
1336 cc->cc_hot = p->hot;
1337 if (v & WSDISPLAY_CURSOR_DOPOS)
1338 stic_set_curpos(si, &p->pos);
1339 }
1340
1341 s = spltty();
1342
1343 if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) {
1344 if (p->enable)
1345 ss->ss_flags |= SS_CURENB;
1346 else
1347 ss->ss_flags &= ~SS_CURENB;
1348 si->si_flags |= SI_CURENB_CHANGED;
1349 }
1350
1351 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
1352 copyin(p->cmap.red, &cc->cc_color[index], count);
1353 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
1354 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
1355 si->si_flags |= SI_CURCMAP_CHANGED;
1356 }
1357
1358 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
1359 memset(cc->cc_image, 0, sizeof(cc->cc_image));
1360 copyin(p->image, cc->cc_image, icount);
1361 copyin(p->mask, cc->cc_image + CURSOR_MAX_SIZE, icount);
1362 si->si_flags |= SI_CURSHAPE_CHANGED;
1363 }
1364
1365 splx(s);
1366
1367 /*
1368 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1369 * must flush immediatley.
1370 */
1371 if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1372 stic_flush(si);
1373
1374 return (0);
1375 #undef cc
1376 }
1377
1378 int
1379 stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1380 {
1381
1382 /* XXX */
1383 return (ENOTTY);
1384 }
1385
1386 void
1387 stic_set_curpos(struct stic_info *si, struct wsdisplay_curpos *curpos)
1388 {
1389 int x, y;
1390
1391 x = curpos->x;
1392 y = curpos->y;
1393
1394 if (y < 0)
1395 y = 0;
1396 else if (y > 1023)
1397 y = 1023;
1398 if (x < 0)
1399 x = 0;
1400 else if (x > 1279)
1401 x = 1279;
1402
1403 si->si_cursor.cc_pos.x = x;
1404 si->si_cursor.cc_pos.y = y;
1405 stic_set_hwcurpos(si);
1406 }
1407
1408 void
1409 stic_set_hwcurpos(struct stic_info *si)
1410 {
1411 volatile u_int32_t *vdac;
1412 int x, y, s;
1413
1414 vdac = si->si_vdac;
1415
1416 x = si->si_cursor.cc_pos.x - si->si_cursor.cc_hot.x;
1417 y = si->si_cursor.cc_pos.y - si->si_cursor.cc_hot.y;
1418 x += STIC_MAGIC_X;
1419 y += STIC_MAGIC_Y;
1420
1421 s = spltty();
1422 SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
1423 REG(vdac, bt_reg) = DUPBYTE0(x); tc_wmb();
1424 REG(vdac, bt_reg) = DUPBYTE1(x); tc_wmb();
1425 REG(vdac, bt_reg) = DUPBYTE0(y); tc_wmb();
1426 REG(vdac, bt_reg) = DUPBYTE1(y); tc_wmb();
1427 splx(s);
1428 }
1429
1430 /*
1431 * STIC control inteface. We have a seperate device for mapping the board,
1432 * because access to the DMA engine means that it's possible to circumvent
1433 * the securelevel mechanism. Given the way devices work in the BSD kernel,
1434 * and given the unfortunate design of the mmap() call it's near impossible
1435 * to protect against this using a shared device (i.e. wsdisplay).
1436 *
1437 * This is a gross hack... Hopefully not too many other devices will need
1438 * it.
1439 */
1440 int
1441 sticopen(dev_t dev, int flag, int mode, struct proc *p)
1442 {
1443 struct stic_info *si;
1444 int s;
1445
1446 if (securelevel > 0)
1447 return (EPERM);
1448 if (minor(dev) >= STIC_MAXDV)
1449 return (ENXIO);
1450 if ((si = stic_info[minor(dev)]) == NULL)
1451 return (ENXIO);
1452
1453 s = spltty();
1454 if ((si->si_flags & SI_DVOPEN) != 0) {
1455 splx(s);
1456 return (EBUSY);
1457 }
1458 si->si_flags |= SI_DVOPEN;
1459 splx(s);
1460
1461 return (0);
1462 }
1463
1464 int
1465 sticclose(dev_t dev, int flag, int mode, struct proc *p)
1466 {
1467 struct stic_info *si;
1468 int s;
1469
1470 si = stic_info[minor(dev)];
1471 s = spltty();
1472 si->si_flags &= ~SI_DVOPEN;
1473 splx(s);
1474
1475 return (0);
1476 }
1477
1478 paddr_t
1479 sticmmap(dev_t dev, off_t offset, int prot)
1480 {
1481 struct stic_info *si;
1482 struct stic_xmap *sxm;
1483 paddr_t pa;
1484
1485 si = stic_info[minor(dev)];
1486 sxm = NULL;
1487
1488 if (securelevel > 0)
1489 return (-1L);
1490 if (si->si_dispmode != WSDISPLAYIO_MODE_MAPPED)
1491 return (-1L);
1492
1493 if (offset < 0)
1494 return ((paddr_t)-1L);
1495
1496 if (offset < sizeof(sxm->sxm_stic)) {
1497 pa = STIC_KSEG_TO_PHYS(si->si_stic);
1498 return (machine_btop(pa + offset));
1499 }
1500 offset -= sizeof(sxm->sxm_stic);
1501
1502 if (offset < sizeof(sxm->sxm_poll)) {
1503 pa = STIC_KSEG_TO_PHYS(si->si_slotbase);
1504 return (machine_btop(pa + offset));
1505 }
1506 offset -= sizeof(sxm->sxm_poll);
1507
1508 if (offset < si->si_buf_size)
1509 return (machine_btop(si->si_buf_phys + offset));
1510
1511 return ((paddr_t)-1L);
1512 }
1513