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