wsdisplay_vcons.c revision 1.6.2.2 1 1.6.2.2 simonb /* $NetBSD: wsdisplay_vcons.c,v 1.6.2.2 2006/04/22 11:39:44 simonb Exp $ */
2 1.6.2.2 simonb
3 1.6.2.2 simonb /*-
4 1.6.2.2 simonb * Copyright (c) 2005, 2006 Michael Lorenz
5 1.6.2.2 simonb * All rights reserved.
6 1.6.2.2 simonb *
7 1.6.2.2 simonb * Redistribution and use in source and binary forms, with or without
8 1.6.2.2 simonb * modification, are permitted provided that the following conditions
9 1.6.2.2 simonb * are met:
10 1.6.2.2 simonb * 1. Redistributions of source code must retain the above copyright
11 1.6.2.2 simonb * notice, this list of conditions and the following disclaimer.
12 1.6.2.2 simonb * 2. Redistributions in binary form must reproduce the above copyright
13 1.6.2.2 simonb * notice, this list of conditions and the following disclaimer in the
14 1.6.2.2 simonb * documentation and/or other materials provided with the distribution.
15 1.6.2.2 simonb * 3. All advertising materials mentioning features or use of this software
16 1.6.2.2 simonb * must display the following acknowledgement:
17 1.6.2.2 simonb * This product includes software developed by the NetBSD
18 1.6.2.2 simonb * Foundation, Inc. and its contributors.
19 1.6.2.2 simonb * 4. Neither the name of The NetBSD Foundation nor the names of its
20 1.6.2.2 simonb * contributors may be used to endorse or promote products derived
21 1.6.2.2 simonb * from this software without specific prior written permission.
22 1.6.2.2 simonb *
23 1.6.2.2 simonb * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24 1.6.2.2 simonb * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 1.6.2.2 simonb * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 1.6.2.2 simonb * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27 1.6.2.2 simonb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 1.6.2.2 simonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 1.6.2.2 simonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 1.6.2.2 simonb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 1.6.2.2 simonb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 1.6.2.2 simonb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 1.6.2.2 simonb * POSSIBILITY OF SUCH DAMAGE.
34 1.6.2.2 simonb */
35 1.6.2.2 simonb
36 1.6.2.2 simonb #include <sys/cdefs.h>
37 1.6.2.2 simonb __KERNEL_RCSID(0, "$NetBSD: wsdisplay_vcons.c,v 1.6.2.2 2006/04/22 11:39:44 simonb Exp $");
38 1.6.2.2 simonb
39 1.6.2.2 simonb #include <sys/param.h>
40 1.6.2.2 simonb #include <sys/systm.h>
41 1.6.2.2 simonb #include <sys/kernel.h>
42 1.6.2.2 simonb #include <sys/buf.h>
43 1.6.2.2 simonb #include <sys/device.h>
44 1.6.2.2 simonb #include <sys/ioctl.h>
45 1.6.2.2 simonb #include <sys/malloc.h>
46 1.6.2.2 simonb #include <sys/mman.h>
47 1.6.2.2 simonb #include <sys/tty.h>
48 1.6.2.2 simonb #include <sys/conf.h>
49 1.6.2.2 simonb #include <sys/proc.h>
50 1.6.2.2 simonb #include <sys/kthread.h>
51 1.6.2.2 simonb #include <sys/tprintf.h>
52 1.6.2.2 simonb
53 1.6.2.2 simonb #include <dev/wscons/wsdisplayvar.h>
54 1.6.2.2 simonb #include <dev/wscons/wsconsio.h>
55 1.6.2.2 simonb #include <dev/wsfont/wsfont.h>
56 1.6.2.2 simonb #include <dev/rasops/rasops.h>
57 1.6.2.2 simonb
58 1.6.2.2 simonb #include <dev/wscons/wsdisplay_vconsvar.h>
59 1.6.2.2 simonb
60 1.6.2.2 simonb static void vcons_dummy_init_screen(void *, struct vcons_screen *, int,
61 1.6.2.2 simonb long *);
62 1.6.2.2 simonb
63 1.6.2.2 simonb static int vcons_ioctl(void *, void *, u_long, caddr_t, int, struct lwp *);
64 1.6.2.2 simonb static int vcons_alloc_screen(void *, const struct wsscreen_descr *, void **,
65 1.6.2.2 simonb int *, int *, long *);
66 1.6.2.2 simonb static void vcons_free_screen(void *, void *);
67 1.6.2.2 simonb static int vcons_show_screen(void *, void *, int, void (*)(void *, int, int),
68 1.6.2.2 simonb void *);
69 1.6.2.2 simonb
70 1.6.2.2 simonb static void vcons_do_switch(struct vcons_data *);
71 1.6.2.2 simonb
72 1.6.2.2 simonb /* methods that work only on text buffers */
73 1.6.2.2 simonb static void vcons_copycols_buffer(void *, int, int, int, int);
74 1.6.2.2 simonb static void vcons_erasecols_buffer(void *, int, int, int, long);
75 1.6.2.2 simonb static void vcons_copyrows_buffer(void *, int, int, int);
76 1.6.2.2 simonb static void vcons_eraserows_buffer(void *, int, int, long);
77 1.6.2.2 simonb static void vcons_putchar_buffer(void *, int, int, u_int, long);
78 1.6.2.2 simonb
79 1.6.2.2 simonb /*
80 1.6.2.2 simonb * actual wrapper methods which call both the _buffer ones above and the
81 1.6.2.2 simonb * driver supplied ones to do the drawing
82 1.6.2.2 simonb */
83 1.6.2.2 simonb static void vcons_copycols(void *, int, int, int, int);
84 1.6.2.2 simonb static void vcons_erasecols(void *, int, int, int, long);
85 1.6.2.2 simonb static void vcons_copyrows(void *, int, int, int);
86 1.6.2.2 simonb static void vcons_eraserows(void *, int, int, long);
87 1.6.2.2 simonb static void vcons_putchar(void *, int, int, u_int, long);
88 1.6.2.2 simonb static void vcons_cursor(void *, int, int, int);
89 1.6.2.2 simonb
90 1.6.2.2 simonb /* support for readin/writing text buffers. For wsmoused */
91 1.6.2.2 simonb static int vcons_putwschar(struct vcons_screen *, struct wsdisplay_char *);
92 1.6.2.2 simonb static int vcons_getwschar(struct vcons_screen *, struct wsdisplay_char *);
93 1.6.2.2 simonb
94 1.6.2.2 simonb static void vcons_lock(struct vcons_screen *);
95 1.6.2.2 simonb static void vcons_unlock(struct vcons_screen *);
96 1.6.2.2 simonb
97 1.6.2.2 simonb
98 1.6.2.2 simonb int
99 1.6.2.2 simonb vcons_init(struct vcons_data *vd, void *cookie, struct wsscreen_descr *def,
100 1.6.2.2 simonb struct wsdisplay_accessops *ao)
101 1.6.2.2 simonb {
102 1.6.2.2 simonb
103 1.6.2.2 simonb /* zero out everything so we can rely on untouched fields being 0 */
104 1.6.2.2 simonb memset(vd, 0, sizeof(struct vcons_data));
105 1.6.2.2 simonb
106 1.6.2.2 simonb vd->cookie = cookie;
107 1.6.2.2 simonb
108 1.6.2.2 simonb vd->init_screen = vcons_dummy_init_screen;
109 1.6.2.2 simonb vd->show_screen_cb = NULL;
110 1.6.2.2 simonb
111 1.6.2.2 simonb /* keep a copy of the accessops that we replace below with our
112 1.6.2.2 simonb * own wrappers */
113 1.6.2.2 simonb vd->ioctl = ao->ioctl;
114 1.6.2.2 simonb
115 1.6.2.2 simonb /* configure the accessops */
116 1.6.2.2 simonb ao->ioctl = vcons_ioctl;
117 1.6.2.2 simonb ao->alloc_screen = vcons_alloc_screen;
118 1.6.2.2 simonb ao->free_screen = vcons_free_screen;
119 1.6.2.2 simonb ao->show_screen = vcons_show_screen;
120 1.6.2.2 simonb
121 1.6.2.2 simonb LIST_INIT(&vd->screens);
122 1.6.2.2 simonb vd->active = NULL;
123 1.6.2.2 simonb vd->wanted = NULL;
124 1.6.2.2 simonb vd->currenttype = def;
125 1.6.2.2 simonb callout_init(&vd->switch_callout);
126 1.6.2.2 simonb
127 1.6.2.2 simonb /*
128 1.6.2.2 simonb * a lock to serialize access to the framebuffer.
129 1.6.2.2 simonb * when switching screens we need to make sure there's no rasops
130 1.6.2.2 simonb * operation in progress
131 1.6.2.2 simonb */
132 1.6.2.2 simonb #ifdef DIAGNOSTIC
133 1.6.2.2 simonb vd->switch_poll_count = 0;
134 1.6.2.2 simonb #endif
135 1.6.2.2 simonb return 0;
136 1.6.2.2 simonb }
137 1.6.2.2 simonb
138 1.6.2.2 simonb static void
139 1.6.2.2 simonb vcons_lock(struct vcons_screen *scr)
140 1.6.2.2 simonb {
141 1.6.2.2 simonb #ifdef VCONS_PARANOIA
142 1.6.2.2 simonb int s;
143 1.6.2.2 simonb
144 1.6.2.2 simonb s = splhigh();
145 1.6.2.2 simonb #endif
146 1.6.2.2 simonb SCREEN_BUSY(scr);
147 1.6.2.2 simonb #ifdef VCONS_PARANOIA
148 1.6.2.2 simonb splx(s);
149 1.6.2.2 simonb #endif
150 1.6.2.2 simonb }
151 1.6.2.2 simonb
152 1.6.2.2 simonb static void
153 1.6.2.2 simonb vcons_unlock(struct vcons_screen *scr)
154 1.6.2.2 simonb {
155 1.6.2.2 simonb #ifdef VCONS_PARANOIA
156 1.6.2.2 simonb int s;
157 1.6.2.2 simonb
158 1.6.2.2 simonb s = splhigh();
159 1.6.2.2 simonb #endif
160 1.6.2.2 simonb SCREEN_IDLE(scr);
161 1.6.2.2 simonb #ifdef VCONS_PARANOIA
162 1.6.2.2 simonb splx(s);
163 1.6.2.2 simonb #endif
164 1.6.2.2 simonb }
165 1.6.2.2 simonb
166 1.6.2.2 simonb static void
167 1.6.2.2 simonb vcons_dummy_init_screen(void *cookie, struct vcons_screen *scr, int exists,
168 1.6.2.2 simonb long *defattr)
169 1.6.2.2 simonb {
170 1.6.2.2 simonb
171 1.6.2.2 simonb /*
172 1.6.2.2 simonb * default init_screen() method.
173 1.6.2.2 simonb * Needs to be overwritten so we bitch and whine in case anyone ends
174 1.6.2.2 simonb * up in here.
175 1.6.2.2 simonb */
176 1.6.2.2 simonb printf("vcons_init_screen: dummy function called. Your driver is "
177 1.6.2.2 simonb "supposed to supply a replacement for proper operation\n");
178 1.6.2.2 simonb }
179 1.6.2.2 simonb
180 1.6.2.2 simonb int
181 1.6.2.2 simonb vcons_init_screen(struct vcons_data *vd, struct vcons_screen *scr,
182 1.6.2.2 simonb int existing, long *defattr)
183 1.6.2.2 simonb {
184 1.6.2.2 simonb struct rasops_info *ri = &scr->scr_ri;
185 1.6.2.2 simonb int cnt, i;
186 1.6.2.2 simonb
187 1.6.2.2 simonb scr->scr_cookie = vd->cookie;
188 1.6.2.2 simonb scr->scr_vd = scr->scr_origvd = vd;
189 1.6.2.2 simonb SCREEN_IDLE(scr);
190 1.6.2.2 simonb
191 1.6.2.2 simonb /*
192 1.6.2.2 simonb * call the driver-supplied init_screen function which is expected
193 1.6.2.2 simonb * to set up rasops_info, override cursor() and probably others
194 1.6.2.2 simonb */
195 1.6.2.2 simonb vd->init_screen(vd->cookie, scr, existing, defattr);
196 1.6.2.2 simonb
197 1.6.2.2 simonb /*
198 1.6.2.2 simonb * save the non virtual console aware rasops and replace them with
199 1.6.2.2 simonb * our wrappers
200 1.6.2.2 simonb */
201 1.6.2.2 simonb vd->eraserows = ri->ri_ops.eraserows;
202 1.6.2.2 simonb vd->copyrows = ri->ri_ops.copyrows;
203 1.6.2.2 simonb vd->erasecols = ri->ri_ops.erasecols;
204 1.6.2.2 simonb vd->copycols = ri->ri_ops.copycols;
205 1.6.2.2 simonb vd->putchar = ri->ri_ops.putchar;
206 1.6.2.2 simonb vd->cursor = ri->ri_ops.cursor;
207 1.6.2.2 simonb
208 1.6.2.2 simonb ri->ri_ops.eraserows = vcons_eraserows;
209 1.6.2.2 simonb ri->ri_ops.copyrows = vcons_copyrows;
210 1.6.2.2 simonb ri->ri_ops.erasecols = vcons_erasecols;
211 1.6.2.2 simonb ri->ri_ops.copycols = vcons_copycols;
212 1.6.2.2 simonb ri->ri_ops.putchar = vcons_putchar;
213 1.6.2.2 simonb ri->ri_ops.cursor = vcons_cursor;
214 1.6.2.2 simonb ri->ri_hw = scr;
215 1.6.2.2 simonb
216 1.6.2.2 simonb /*
217 1.6.2.2 simonb * we allocate both chars and attributes in one chunk, attributes first
218 1.6.2.2 simonb * because they have the (potentially) bigger alignment
219 1.6.2.2 simonb */
220 1.6.2.2 simonb cnt = ri->ri_rows * ri->ri_cols;
221 1.6.2.2 simonb scr->scr_attrs = (long *)malloc(cnt * (sizeof(long) +
222 1.6.2.2 simonb sizeof(uint16_t)), M_DEVBUF, M_WAITOK);
223 1.6.2.2 simonb if (scr->scr_attrs == NULL)
224 1.6.2.2 simonb return ENOMEM;
225 1.6.2.2 simonb
226 1.6.2.2 simonb scr->scr_chars = (uint16_t *)&scr->scr_attrs[cnt];
227 1.6.2.2 simonb
228 1.6.2.2 simonb ri->ri_ops.allocattr(ri, WS_DEFAULT_FG, WS_DEFAULT_BG, 0, defattr);
229 1.6.2.2 simonb scr->scr_defattr = *defattr;
230 1.6.2.2 simonb
231 1.6.2.2 simonb /*
232 1.6.2.2 simonb * fill the attribute buffer with *defattr, chars with 0x20
233 1.6.2.2 simonb * since we don't know if the driver tries to mimic firmware output or
234 1.6.2.2 simonb * reset everything we do nothing to VRAM here, any driver that feels
235 1.6.2.2 simonb * the need to clear screen or something will have to do it on its own
236 1.6.2.2 simonb * Additional screens will start out in the background anyway so
237 1.6.2.2 simonb * cleaning or not only really affects the initial console screen
238 1.6.2.2 simonb */
239 1.6.2.2 simonb for (i = 0; i < cnt; i++) {
240 1.6.2.2 simonb scr->scr_attrs[i] = *defattr;
241 1.6.2.2 simonb scr->scr_chars[i] = 0x20;
242 1.6.2.2 simonb }
243 1.6.2.2 simonb
244 1.6.2.2 simonb if(vd->active == NULL) {
245 1.6.2.2 simonb vd->active = scr;
246 1.6.2.2 simonb SCREEN_VISIBLE(scr);
247 1.6.2.2 simonb }
248 1.6.2.2 simonb
249 1.6.2.2 simonb if (existing) {
250 1.6.2.2 simonb SCREEN_VISIBLE(scr);
251 1.6.2.2 simonb vd->active = scr;
252 1.6.2.2 simonb } else {
253 1.6.2.2 simonb SCREEN_INVISIBLE(scr);
254 1.6.2.2 simonb }
255 1.6.2.2 simonb
256 1.6.2.2 simonb LIST_INSERT_HEAD(&vd->screens, scr, next);
257 1.6.2.2 simonb return 0;
258 1.6.2.2 simonb }
259 1.6.2.2 simonb
260 1.6.2.2 simonb static void
261 1.6.2.2 simonb vcons_do_switch(struct vcons_data *vd)
262 1.6.2.2 simonb {
263 1.6.2.2 simonb struct vcons_screen *scr, *oldscr;
264 1.6.2.2 simonb
265 1.6.2.2 simonb scr = vd->wanted;
266 1.6.2.2 simonb if (!scr) {
267 1.6.2.2 simonb printf("vcons_switch_screen: disappeared\n");
268 1.6.2.2 simonb vd->switch_cb(vd->switch_cb_arg, EIO, 0);
269 1.6.2.2 simonb return;
270 1.6.2.2 simonb }
271 1.6.2.2 simonb oldscr = vd->active; /* can be NULL! */
272 1.6.2.2 simonb
273 1.6.2.2 simonb /*
274 1.6.2.2 simonb * if there's an old, visible screen we mark it invisible and wait
275 1.6.2.2 simonb * until it's not busy so we can safely switch
276 1.6.2.2 simonb */
277 1.6.2.2 simonb if (oldscr != NULL) {
278 1.6.2.2 simonb SCREEN_INVISIBLE(oldscr);
279 1.6.2.2 simonb if (SCREEN_IS_BUSY(oldscr)) {
280 1.6.2.2 simonb callout_reset(&vd->switch_callout, 1,
281 1.6.2.2 simonb (void(*)(void *))vcons_do_switch, vd);
282 1.6.2.2 simonb #ifdef DIAGNOSTIC
283 1.6.2.2 simonb /* bitch if we wait too long */
284 1.6.2.2 simonb vd->switch_poll_count++;
285 1.6.2.2 simonb if (vd->switch_poll_count > 100) {
286 1.6.2.2 simonb panic("vcons: screen still busy");
287 1.6.2.2 simonb }
288 1.6.2.2 simonb #endif
289 1.6.2.2 simonb return;
290 1.6.2.2 simonb }
291 1.6.2.2 simonb /* invisible screen -> no visible cursor image */
292 1.6.2.2 simonb oldscr->scr_ri.ri_flg &= ~RI_CURSOR;
293 1.6.2.2 simonb #ifdef DIAGNOSTIC
294 1.6.2.2 simonb vd->switch_poll_count = 0;
295 1.6.2.2 simonb #endif
296 1.6.2.2 simonb }
297 1.6.2.2 simonb
298 1.6.2.2 simonb if (scr == oldscr)
299 1.6.2.2 simonb return;
300 1.6.2.2 simonb
301 1.6.2.2 simonb #ifdef DIAGNOSTIC
302 1.6.2.2 simonb if (SCREEN_IS_VISIBLE(scr))
303 1.6.2.2 simonb panic("vcons_switch_screen: already active");
304 1.6.2.2 simonb #endif
305 1.6.2.2 simonb
306 1.6.2.2 simonb #ifdef notyet
307 1.6.2.2 simonb if (vd->currenttype != type) {
308 1.6.2.2 simonb vcons_set_screentype(vd, type);
309 1.6.2.2 simonb vd->currenttype = type;
310 1.6.2.2 simonb }
311 1.6.2.2 simonb #endif
312 1.6.2.2 simonb
313 1.6.2.2 simonb SCREEN_VISIBLE(scr);
314 1.6.2.2 simonb vd->active = scr;
315 1.6.2.2 simonb vd->wanted = NULL;
316 1.6.2.2 simonb
317 1.6.2.2 simonb if (vd->show_screen_cb != NULL)
318 1.6.2.2 simonb vd->show_screen_cb(scr);
319 1.6.2.2 simonb
320 1.6.2.2 simonb if ((scr->scr_flags & VCONS_NO_REDRAW) == 0)
321 1.6.2.2 simonb vcons_redraw_screen(scr);
322 1.6.2.2 simonb
323 1.6.2.2 simonb if (vd->switch_cb)
324 1.6.2.2 simonb vd->switch_cb(vd->switch_cb_arg, 0, 0);
325 1.6.2.2 simonb }
326 1.6.2.2 simonb
327 1.6.2.2 simonb void
328 1.6.2.2 simonb vcons_redraw_screen(struct vcons_screen *scr)
329 1.6.2.2 simonb {
330 1.6.2.2 simonb uint16_t *charptr = scr->scr_chars;
331 1.6.2.2 simonb long *attrptr = scr->scr_attrs;
332 1.6.2.2 simonb struct rasops_info *ri = &scr->scr_ri;
333 1.6.2.2 simonb int i, j, offset;
334 1.6.2.2 simonb
335 1.6.2.2 simonb vcons_lock(scr);
336 1.6.2.2 simonb if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
337 1.6.2.2 simonb
338 1.6.2.2 simonb /*
339 1.6.2.2 simonb * only clear the screen when RI_FULLCLEAR is set since we're
340 1.6.2.2 simonb * going to overwrite every single character cell anyway
341 1.6.2.2 simonb */
342 1.6.2.2 simonb if (ri->ri_flg & RI_FULLCLEAR) {
343 1.6.2.2 simonb scr->scr_vd->eraserows(ri, 0, ri->ri_rows,
344 1.6.2.2 simonb scr->scr_defattr);
345 1.6.2.2 simonb }
346 1.6.2.2 simonb
347 1.6.2.2 simonb /* redraw the screen */
348 1.6.2.2 simonb offset = 0;
349 1.6.2.2 simonb for (i = 0; i < ri->ri_rows; i++) {
350 1.6.2.2 simonb for (j = 0; j < ri->ri_cols; j++) {
351 1.6.2.2 simonb /*
352 1.6.2.2 simonb * no need to use the wrapper function - we
353 1.6.2.2 simonb * don't change any characters or attributes
354 1.6.2.2 simonb * and we already made sure the screen we're
355 1.6.2.2 simonb * working on is visible
356 1.6.2.2 simonb */
357 1.6.2.2 simonb scr->scr_vd->putchar(ri, i, j,
358 1.6.2.2 simonb charptr[offset], attrptr[offset]);
359 1.6.2.2 simonb offset++;
360 1.6.2.2 simonb }
361 1.6.2.2 simonb }
362 1.6.2.2 simonb ri->ri_flg &= ~RI_CURSOR;
363 1.6.2.2 simonb scr->scr_vd->cursor(ri, 1, ri->ri_crow, ri->ri_ccol);
364 1.6.2.2 simonb }
365 1.6.2.2 simonb vcons_unlock(scr);
366 1.6.2.2 simonb }
367 1.6.2.2 simonb
368 1.6.2.2 simonb static int
369 1.6.2.2 simonb vcons_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flag,
370 1.6.2.2 simonb struct lwp *l)
371 1.6.2.2 simonb {
372 1.6.2.2 simonb struct vcons_data *vd = v;
373 1.6.2.2 simonb int error;
374 1.6.2.2 simonb
375 1.6.2.2 simonb switch (cmd) {
376 1.6.2.2 simonb case WSDISPLAYIO_GETWSCHAR:
377 1.6.2.2 simonb error = vcons_getwschar((struct vcons_screen *)vs,
378 1.6.2.2 simonb (struct wsdisplay_char *)data);
379 1.6.2.2 simonb break;
380 1.6.2.2 simonb
381 1.6.2.2 simonb case WSDISPLAYIO_PUTWSCHAR:
382 1.6.2.2 simonb error = vcons_putwschar((struct vcons_screen *)vs,
383 1.6.2.2 simonb (struct wsdisplay_char *)data);
384 1.6.2.2 simonb break;
385 1.6.2.2 simonb
386 1.6.2.2 simonb default:
387 1.6.2.2 simonb if (vd->ioctl != NULL)
388 1.6.2.2 simonb error = (*vd->ioctl)(v, vs, cmd, data, flag, l);
389 1.6.2.2 simonb else
390 1.6.2.2 simonb error = EPASSTHROUGH;
391 1.6.2.2 simonb }
392 1.6.2.2 simonb
393 1.6.2.2 simonb return error;
394 1.6.2.2 simonb }
395 1.6.2.2 simonb
396 1.6.2.2 simonb static int
397 1.6.2.2 simonb vcons_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
398 1.6.2.2 simonb int *curxp, int *curyp, long *defattrp)
399 1.6.2.2 simonb {
400 1.6.2.2 simonb struct vcons_data *vd = v;
401 1.6.2.2 simonb struct vcons_screen *scr;
402 1.6.2.2 simonb int ret;
403 1.6.2.2 simonb
404 1.6.2.2 simonb scr = malloc(sizeof(struct vcons_screen), M_DEVBUF, M_WAITOK | M_ZERO);
405 1.6.2.2 simonb if (scr == NULL)
406 1.6.2.2 simonb return ENOMEM;
407 1.6.2.2 simonb
408 1.6.2.2 simonb scr->scr_flags = 0;
409 1.6.2.2 simonb scr->scr_status = 0;
410 1.6.2.2 simonb scr->scr_busy = 0;
411 1.6.2.2 simonb scr->scr_type = type;
412 1.6.2.2 simonb
413 1.6.2.2 simonb ret = vcons_init_screen(vd, scr, 0, defattrp);
414 1.6.2.2 simonb if (ret != 0) {
415 1.6.2.2 simonb free(scr, M_DEVBUF);
416 1.6.2.2 simonb return ret;
417 1.6.2.2 simonb }
418 1.6.2.2 simonb
419 1.6.2.2 simonb if (vd->active == NULL) {
420 1.6.2.2 simonb SCREEN_VISIBLE(scr);
421 1.6.2.2 simonb vd->active = scr;
422 1.6.2.2 simonb vd->currenttype = type;
423 1.6.2.2 simonb }
424 1.6.2.2 simonb
425 1.6.2.2 simonb *cookiep = scr;
426 1.6.2.2 simonb *curxp = scr->scr_ri.ri_ccol;
427 1.6.2.2 simonb *curyp = scr->scr_ri.ri_crow;
428 1.6.2.2 simonb return 0;
429 1.6.2.2 simonb }
430 1.6.2.2 simonb
431 1.6.2.2 simonb static void
432 1.6.2.2 simonb vcons_free_screen(void *v, void *cookie)
433 1.6.2.2 simonb {
434 1.6.2.2 simonb struct vcons_data *vd = v;
435 1.6.2.2 simonb struct vcons_screen *scr = cookie;
436 1.6.2.2 simonb
437 1.6.2.2 simonb vcons_lock(scr);
438 1.6.2.2 simonb /* there should be no rasops activity here */
439 1.6.2.2 simonb
440 1.6.2.2 simonb LIST_REMOVE(scr, next);
441 1.6.2.2 simonb
442 1.6.2.2 simonb if ((scr->scr_flags & VCONS_SCREEN_IS_STATIC) == 0) {
443 1.6.2.2 simonb free(scr->scr_attrs, M_DEVBUF);
444 1.6.2.2 simonb free(scr, M_DEVBUF);
445 1.6.2.2 simonb } else {
446 1.6.2.2 simonb /*
447 1.6.2.2 simonb * maybe we should just restore the old rasops_info methods
448 1.6.2.2 simonb * and free the character/attribute buffer here?
449 1.6.2.2 simonb */
450 1.6.2.2 simonb #ifdef VCONS_DEBUG
451 1.6.2.2 simonb panic("vcons_free_screen: console");
452 1.6.2.2 simonb #else
453 1.6.2.2 simonb printf("vcons_free_screen: console\n");
454 1.6.2.2 simonb #endif
455 1.6.2.2 simonb }
456 1.6.2.2 simonb
457 1.6.2.2 simonb if (vd->active == scr)
458 1.6.2.2 simonb vd->active = NULL;
459 1.6.2.2 simonb }
460 1.6.2.2 simonb
461 1.6.2.2 simonb static int
462 1.6.2.2 simonb vcons_show_screen(void *v, void *cookie, int waitok,
463 1.6.2.2 simonb void (*cb)(void *, int, int), void *cb_arg)
464 1.6.2.2 simonb {
465 1.6.2.2 simonb struct vcons_data *vd = v;
466 1.6.2.2 simonb struct vcons_screen *scr;
467 1.6.2.2 simonb
468 1.6.2.2 simonb scr = cookie;
469 1.6.2.2 simonb if (scr == vd->active)
470 1.6.2.2 simonb return 0;
471 1.6.2.2 simonb
472 1.6.2.2 simonb vd->wanted = scr;
473 1.6.2.2 simonb vd->switch_cb = cb;
474 1.6.2.2 simonb vd->switch_cb_arg = cb_arg;
475 1.6.2.2 simonb if (cb) {
476 1.6.2.2 simonb callout_reset(&vd->switch_callout, 0,
477 1.6.2.2 simonb (void(*)(void *))vcons_do_switch, vd);
478 1.6.2.2 simonb return EAGAIN;
479 1.6.2.2 simonb }
480 1.6.2.2 simonb
481 1.6.2.2 simonb vcons_do_switch(vd);
482 1.6.2.2 simonb return 0;
483 1.6.2.2 simonb }
484 1.6.2.2 simonb
485 1.6.2.2 simonb /* wrappers for rasops_info methods */
486 1.6.2.2 simonb
487 1.6.2.2 simonb static void
488 1.6.2.2 simonb vcons_copycols_buffer(void *cookie, int row, int srccol, int dstcol, int ncols)
489 1.6.2.2 simonb {
490 1.6.2.2 simonb struct rasops_info *ri = cookie;
491 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
492 1.6.2.2 simonb int from = srccol + row * ri->ri_cols;
493 1.6.2.2 simonb int to = dstcol + row * ri->ri_cols;
494 1.6.2.2 simonb
495 1.6.2.2 simonb memmove(&scr->scr_attrs[to], &scr->scr_attrs[from],
496 1.6.2.2 simonb ncols * sizeof(long));
497 1.6.2.2 simonb memmove(&scr->scr_chars[to], &scr->scr_chars[from],
498 1.6.2.2 simonb ncols * sizeof(uint16_t));
499 1.6.2.2 simonb }
500 1.6.2.2 simonb
501 1.6.2.2 simonb static void
502 1.6.2.2 simonb vcons_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
503 1.6.2.2 simonb {
504 1.6.2.2 simonb struct rasops_info *ri = cookie;
505 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
506 1.6.2.2 simonb
507 1.6.2.2 simonb vcons_copycols_buffer(cookie, row, srccol, dstcol, ncols);
508 1.6.2.2 simonb
509 1.6.2.2 simonb vcons_lock(scr);
510 1.6.2.2 simonb if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
511 1.6.2.2 simonb scr->scr_vd->copycols(cookie, row, srccol, dstcol, ncols);
512 1.6.2.2 simonb }
513 1.6.2.2 simonb vcons_unlock(scr);
514 1.6.2.2 simonb }
515 1.6.2.2 simonb
516 1.6.2.2 simonb static void
517 1.6.2.2 simonb vcons_erasecols_buffer(void *cookie, int row, int startcol, int ncols, long fillattr)
518 1.6.2.2 simonb {
519 1.6.2.2 simonb struct rasops_info *ri = cookie;
520 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
521 1.6.2.2 simonb int start = startcol + row * ri->ri_cols;
522 1.6.2.2 simonb int end = start + ncols, i;
523 1.6.2.2 simonb
524 1.6.2.2 simonb for (i = start; i < end; i++) {
525 1.6.2.2 simonb scr->scr_attrs[i] = fillattr;
526 1.6.2.2 simonb scr->scr_chars[i] = 0x20;
527 1.6.2.2 simonb }
528 1.6.2.2 simonb }
529 1.6.2.2 simonb
530 1.6.2.2 simonb static void
531 1.6.2.2 simonb vcons_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
532 1.6.2.2 simonb {
533 1.6.2.2 simonb struct rasops_info *ri = cookie;
534 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
535 1.6.2.2 simonb
536 1.6.2.2 simonb vcons_erasecols_buffer(cookie, row, startcol, ncols, fillattr);
537 1.6.2.2 simonb
538 1.6.2.2 simonb vcons_lock(scr);
539 1.6.2.2 simonb if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
540 1.6.2.2 simonb scr->scr_vd->erasecols(cookie, row, startcol, ncols,
541 1.6.2.2 simonb fillattr);
542 1.6.2.2 simonb }
543 1.6.2.2 simonb vcons_unlock(scr);
544 1.6.2.2 simonb }
545 1.6.2.2 simonb
546 1.6.2.2 simonb static void
547 1.6.2.2 simonb vcons_copyrows_buffer(void *cookie, int srcrow, int dstrow, int nrows)
548 1.6.2.2 simonb {
549 1.6.2.2 simonb struct rasops_info *ri = cookie;
550 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
551 1.6.2.2 simonb int from, to, len;
552 1.6.2.2 simonb
553 1.6.2.2 simonb from = ri->ri_cols * srcrow;
554 1.6.2.2 simonb to = ri->ri_cols * dstrow;
555 1.6.2.2 simonb len = ri->ri_cols * nrows;
556 1.6.2.2 simonb
557 1.6.2.2 simonb memmove(&scr->scr_attrs[to], &scr->scr_attrs[from],
558 1.6.2.2 simonb len * sizeof(long));
559 1.6.2.2 simonb memmove(&scr->scr_chars[to], &scr->scr_chars[from],
560 1.6.2.2 simonb len * sizeof(uint16_t));
561 1.6.2.2 simonb }
562 1.6.2.2 simonb
563 1.6.2.2 simonb static void
564 1.6.2.2 simonb vcons_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
565 1.6.2.2 simonb {
566 1.6.2.2 simonb struct rasops_info *ri = cookie;
567 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
568 1.6.2.2 simonb
569 1.6.2.2 simonb vcons_copyrows_buffer(cookie, srcrow, dstrow, nrows);
570 1.6.2.2 simonb
571 1.6.2.2 simonb vcons_lock(scr);
572 1.6.2.2 simonb if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
573 1.6.2.2 simonb scr->scr_vd->copyrows(cookie, srcrow, dstrow, nrows);
574 1.6.2.2 simonb }
575 1.6.2.2 simonb vcons_unlock(scr);
576 1.6.2.2 simonb }
577 1.6.2.2 simonb
578 1.6.2.2 simonb static void
579 1.6.2.2 simonb vcons_eraserows_buffer(void *cookie, int row, int nrows, long fillattr)
580 1.6.2.2 simonb {
581 1.6.2.2 simonb struct rasops_info *ri = cookie;
582 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
583 1.6.2.2 simonb int start, end, i;
584 1.6.2.2 simonb
585 1.6.2.2 simonb start = ri->ri_cols * row;
586 1.6.2.2 simonb end = ri->ri_cols * (row + nrows);
587 1.6.2.2 simonb
588 1.6.2.2 simonb for (i = start; i < end; i++) {
589 1.6.2.2 simonb scr->scr_attrs[i] = fillattr;
590 1.6.2.2 simonb scr->scr_chars[i] = 0x20;
591 1.6.2.2 simonb }
592 1.6.2.2 simonb }
593 1.6.2.2 simonb
594 1.6.2.2 simonb static void
595 1.6.2.2 simonb vcons_eraserows(void *cookie, int row, int nrows, long fillattr)
596 1.6.2.2 simonb {
597 1.6.2.2 simonb struct rasops_info *ri = cookie;
598 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
599 1.6.2.2 simonb
600 1.6.2.2 simonb vcons_eraserows_buffer(cookie, row, nrows, fillattr);
601 1.6.2.2 simonb
602 1.6.2.2 simonb vcons_lock(scr);
603 1.6.2.2 simonb if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
604 1.6.2.2 simonb scr->scr_vd->eraserows(cookie, row, nrows, fillattr);
605 1.6.2.2 simonb }
606 1.6.2.2 simonb vcons_unlock(scr);
607 1.6.2.2 simonb }
608 1.6.2.2 simonb
609 1.6.2.2 simonb static void
610 1.6.2.2 simonb vcons_putchar_buffer(void *cookie, int row, int col, u_int c, long attr)
611 1.6.2.2 simonb {
612 1.6.2.2 simonb struct rasops_info *ri = cookie;
613 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
614 1.6.2.2 simonb int pos;
615 1.6.2.2 simonb
616 1.6.2.2 simonb if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) &&
617 1.6.2.2 simonb (col < ri->ri_cols)) {
618 1.6.2.2 simonb pos = col + row * ri->ri_cols;
619 1.6.2.2 simonb scr->scr_attrs[pos] = attr;
620 1.6.2.2 simonb scr->scr_chars[pos] = c;
621 1.6.2.2 simonb }
622 1.6.2.2 simonb }
623 1.6.2.2 simonb
624 1.6.2.2 simonb static void
625 1.6.2.2 simonb vcons_putchar(void *cookie, int row, int col, u_int c, long attr)
626 1.6.2.2 simonb {
627 1.6.2.2 simonb struct rasops_info *ri = cookie;
628 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
629 1.6.2.2 simonb
630 1.6.2.2 simonb vcons_putchar_buffer(cookie, row, col, c, attr);
631 1.6.2.2 simonb
632 1.6.2.2 simonb vcons_lock(scr);
633 1.6.2.2 simonb if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
634 1.6.2.2 simonb scr->scr_vd->putchar(cookie, row, col, c, attr);
635 1.6.2.2 simonb }
636 1.6.2.2 simonb vcons_unlock(scr);
637 1.6.2.2 simonb }
638 1.6.2.2 simonb
639 1.6.2.2 simonb static void
640 1.6.2.2 simonb vcons_cursor(void *cookie, int on, int row, int col)
641 1.6.2.2 simonb {
642 1.6.2.2 simonb struct rasops_info *ri = cookie;
643 1.6.2.2 simonb struct vcons_screen *scr = ri->ri_hw;
644 1.6.2.2 simonb
645 1.6.2.2 simonb vcons_lock(scr);
646 1.6.2.2 simonb if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
647 1.6.2.2 simonb scr->scr_vd->cursor(cookie, on, row, col);
648 1.6.2.2 simonb } else {
649 1.6.2.2 simonb scr->scr_ri.ri_crow = row;
650 1.6.2.2 simonb scr->scr_ri.ri_ccol = col;
651 1.6.2.2 simonb }
652 1.6.2.2 simonb vcons_unlock(scr);
653 1.6.2.2 simonb }
654 1.6.2.2 simonb
655 1.6.2.2 simonb /* methods to read/write characters via ioctl() */
656 1.6.2.2 simonb
657 1.6.2.2 simonb static int
658 1.6.2.2 simonb vcons_putwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc)
659 1.6.2.2 simonb {
660 1.6.2.2 simonb long attr;
661 1.6.2.2 simonb struct rasops_info *ri;
662 1.6.2.2 simonb
663 1.6.2.2 simonb KASSERT(scr != NULL && wsc != NULL);
664 1.6.2.2 simonb
665 1.6.2.2 simonb ri = &scr->scr_ri;
666 1.6.2.2 simonb
667 1.6.2.2 simonb ri->ri_ops.allocattr(ri, wsc->foreground, wsc->background,
668 1.6.2.2 simonb wsc->flags, &attr);
669 1.6.2.2 simonb vcons_putchar(ri, wsc->row, wsc->col, wsc->letter, attr);
670 1.6.2.2 simonb return 0;
671 1.6.2.2 simonb }
672 1.6.2.2 simonb
673 1.6.2.2 simonb static int
674 1.6.2.2 simonb vcons_getwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc)
675 1.6.2.2 simonb {
676 1.6.2.2 simonb int offset;
677 1.6.2.2 simonb long attr;
678 1.6.2.2 simonb struct rasops_info *ri;
679 1.6.2.2 simonb
680 1.6.2.2 simonb KASSERT(scr != NULL && wsc != NULL);
681 1.6.2.2 simonb
682 1.6.2.2 simonb ri = &scr->scr_ri;
683 1.6.2.2 simonb offset = ri->ri_cols * wsc->row + wsc->col;
684 1.6.2.2 simonb wsc->letter = scr->scr_chars[offset];
685 1.6.2.2 simonb attr = scr->scr_attrs[offset];
686 1.6.2.2 simonb
687 1.6.2.2 simonb /*
688 1.6.2.2 simonb * this is ugly. We need to break up an attribute into colours and
689 1.6.2.2 simonb * flags but there's no rasops method to do that so we must rely on
690 1.6.2.2 simonb * the 'canonical' encoding.
691 1.6.2.2 simonb */
692 1.6.2.2 simonb wsc->foreground = (attr & 0xff000000) >> 24;
693 1.6.2.2 simonb wsc->background = (attr & 0x00ff0000) >> 16;
694 1.6.2.2 simonb wsc->flags = (attr & 0x0000ff00) >> 8;
695 1.6.2.2 simonb return 0;
696 1.6.2.2 simonb }
697