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