1 /* $NetBSD: wsdisplay_vcons.c,v 1.15 2007/10/17 22:13:56 joerg Exp $ */
4 * Copyright (c) 2005, 2006 Michael Lorenz
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: wsdisplay_vcons.c,v 1.15 2007/10/17 22:13:56 joerg Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
36 #include <sys/device.h>
37 #include <sys/ioctl.h>
38 #include <sys/malloc.h>
43 #include <sys/kthread.h>
44 #include <sys/tprintf.h>
46 #include <dev/wscons/wsdisplayvar.h>
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wsfont/wsfont.h>
49 #include <dev/rasops/rasops.h>
51 #include <dev/wscons/wsdisplay_vconsvar.h>
53 #include "opt_wsemul.h"
54 #include "opt_wsdisplay_compat.h"
55 #include "opt_vcons.h"
57 static void vcons_dummy_init_screen(void *, struct vcons_screen
*, int,
60 static int vcons_ioctl(void *, void *, u_long
, void *, int, struct lwp
*);
61 static int vcons_alloc_screen(void *, const struct wsscreen_descr
*, void **,
62 int *, int *, long *);
63 static void vcons_free_screen(void *, void *);
64 static int vcons_show_screen(void *, void *, int, void (*)(void *, int, int),
67 #ifdef WSDISPLAY_SCROLLSUPPORT
68 static void vcons_scroll(void *, void *, int);
69 static void vcons_do_scroll(struct vcons_screen
*);
72 static void vcons_do_switch(void *);
74 /* methods that work only on text buffers */
75 static void vcons_copycols_buffer(void *, int, int, int, int);
76 static void vcons_erasecols_buffer(void *, int, int, int, long);
77 static void vcons_copyrows_buffer(void *, int, int, int);
78 static void vcons_eraserows_buffer(void *, int, int, long);
79 static void vcons_putchar_buffer(void *, int, int, u_int
, long);
82 * actual wrapper methods which call both the _buffer ones above and the
83 * driver supplied ones to do the drawing
85 static void vcons_copycols(void *, int, int, int, int);
86 static void vcons_erasecols(void *, int, int, int, long);
87 static void vcons_copyrows(void *, int, int, int);
88 static void vcons_eraserows(void *, int, int, long);
89 static void vcons_putchar(void *, int, int, u_int
, long);
90 static void vcons_cursor(void *, int, int, int);
92 /* support for reading/writing text buffers. For wsmoused */
93 static int vcons_putwschar(struct vcons_screen
*, struct wsdisplay_char
*);
94 static int vcons_getwschar(struct vcons_screen
*, struct wsdisplay_char
*);
96 static void vcons_lock(struct vcons_screen
*);
97 static void vcons_unlock(struct vcons_screen
*);
99 #ifdef VCONS_SWITCH_ASYNC
100 static void vcons_kthread(void *);
104 vcons_init(struct vcons_data
*vd
, void *cookie
, struct wsscreen_descr
*def
,
105 struct wsdisplay_accessops
*ao
)
108 /* zero out everything so we can rely on untouched fields being 0 */
109 memset(vd
, 0, sizeof(struct vcons_data
));
113 vd
->init_screen
= vcons_dummy_init_screen
;
114 vd
->show_screen_cb
= NULL
;
116 /* keep a copy of the accessops that we replace below with our
118 vd
->ioctl
= ao
->ioctl
;
120 /* configure the accessops */
121 ao
->ioctl
= vcons_ioctl
;
122 ao
->alloc_screen
= vcons_alloc_screen
;
123 ao
->free_screen
= vcons_free_screen
;
124 ao
->show_screen
= vcons_show_screen
;
125 #ifdef WSDISPLAY_SCROLLSUPPORT
126 ao
->scroll
= vcons_scroll
;
129 LIST_INIT(&vd
->screens
);
132 vd
->currenttype
= def
;
133 callout_init(&vd
->switch_callout
, 0);
134 callout_setfunc(&vd
->switch_callout
, vcons_do_switch
, vd
);
137 * a lock to serialize access to the framebuffer.
138 * when switching screens we need to make sure there's no rasops
139 * operation in progress
142 vd
->switch_poll_count
= 0;
144 #ifdef VCONS_SWITCH_ASYNC
145 kthread_create(PRI_NONE
, 0, NULL
, vcons_kthread
, vd
,
146 &vd
->redraw_thread
, "vcons_draw");
152 vcons_lock(struct vcons_screen
*scr
)
154 #ifdef VCONS_PARANOIA
160 #ifdef VCONS_PARANOIA
166 vcons_unlock(struct vcons_screen
*scr
)
168 #ifdef VCONS_PARANOIA
174 #ifdef VCONS_PARANOIA
177 #ifdef VCONS_SWITCH_ASYNC
178 wakeup(&scr
->scr_vd
->done_drawing
);
183 vcons_dummy_init_screen(void *cookie
,
184 struct vcons_screen
*scr
, int exists
,
189 * default init_screen() method.
190 * Needs to be overwritten so we bitch and whine in case anyone ends
193 printf("vcons_init_screen: dummy function called. Your driver is "
194 "supposed to supply a replacement for proper operation\n");
198 vcons_init_screen(struct vcons_data
*vd
, struct vcons_screen
*scr
,
199 int existing
, long *defattr
)
201 struct rasops_info
*ri
= &scr
->scr_ri
;
204 scr
->scr_cookie
= vd
->cookie
;
205 scr
->scr_vd
= scr
->scr_origvd
= vd
;
209 * call the driver-supplied init_screen function which is expected
210 * to set up rasops_info, override cursor() and probably others
212 vd
->init_screen(vd
->cookie
, scr
, existing
, defattr
);
215 * save the non virtual console aware rasops and replace them with
218 vd
->eraserows
= ri
->ri_ops
.eraserows
;
219 vd
->copyrows
= ri
->ri_ops
.copyrows
;
220 vd
->erasecols
= ri
->ri_ops
.erasecols
;
221 vd
->copycols
= ri
->ri_ops
.copycols
;
222 vd
->putchar
= ri
->ri_ops
.putchar
;
223 vd
->cursor
= ri
->ri_ops
.cursor
;
225 ri
->ri_ops
.eraserows
= vcons_eraserows
;
226 ri
->ri_ops
.copyrows
= vcons_copyrows
;
227 ri
->ri_ops
.erasecols
= vcons_erasecols
;
228 ri
->ri_ops
.copycols
= vcons_copycols
;
229 ri
->ri_ops
.putchar
= vcons_putchar
;
230 ri
->ri_ops
.cursor
= vcons_cursor
;
234 * we allocate both chars and attributes in one chunk, attributes first
235 * because they have the (potentially) bigger alignment
237 #ifdef WSDISPLAY_SCROLLSUPPORT
238 cnt
= (ri
->ri_rows
+ WSDISPLAY_SCROLLBACK_LINES
) * ri
->ri_cols
;
239 scr
->scr_lines_in_buffer
= WSDISPLAY_SCROLLBACK_LINES
;
240 scr
->scr_current_line
= 0;
241 scr
->scr_line_wanted
= 0;
242 scr
->scr_offset_to_zero
= ri
->ri_cols
* WSDISPLAY_SCROLLBACK_LINES
;
243 scr
->scr_current_offset
= scr
->scr_offset_to_zero
;
245 cnt
= ri
->ri_rows
* ri
->ri_cols
;
247 scr
->scr_attrs
= (long *)malloc(cnt
* (sizeof(long) +
248 sizeof(uint16_t)), M_DEVBUF
, M_WAITOK
);
249 if (scr
->scr_attrs
== NULL
)
252 scr
->scr_chars
= (uint16_t *)&scr
->scr_attrs
[cnt
];
254 ri
->ri_ops
.allocattr(ri
, WS_DEFAULT_FG
, WS_DEFAULT_BG
, 0, defattr
);
255 scr
->scr_defattr
= *defattr
;
258 * fill the attribute buffer with *defattr, chars with 0x20
259 * since we don't know if the driver tries to mimic firmware output or
260 * reset everything we do nothing to VRAM here, any driver that feels
261 * the need to clear screen or something will have to do it on its own
262 * Additional screens will start out in the background anyway so
263 * cleaning or not only really affects the initial console screen
265 for (i
= 0; i
< cnt
; i
++) {
266 scr
->scr_attrs
[i
] = *defattr
;
267 scr
->scr_chars
[i
] = 0x20;
270 if(vd
->active
== NULL
) {
279 SCREEN_INVISIBLE(scr
);
282 LIST_INSERT_HEAD(&vd
->screens
, scr
, next
);
287 vcons_do_switch(void *arg
)
289 struct vcons_data
*vd
= arg
;
290 struct vcons_screen
*scr
, *oldscr
;
294 printf("vcons_switch_screen: disappeared\n");
295 vd
->switch_cb(vd
->switch_cb_arg
, EIO
, 0);
298 oldscr
= vd
->active
; /* can be NULL! */
301 * if there's an old, visible screen we mark it invisible and wait
302 * until it's not busy so we can safely switch
304 if (oldscr
!= NULL
) {
305 SCREEN_INVISIBLE(oldscr
);
306 if (SCREEN_IS_BUSY(oldscr
)) {
307 callout_schedule(&vd
->switch_callout
, 1);
309 /* bitch if we wait too long */
310 vd
->switch_poll_count
++;
311 if (vd
->switch_poll_count
> 100) {
312 panic("vcons: screen still busy");
317 /* invisible screen -> no visible cursor image */
318 oldscr
->scr_ri
.ri_flg
&= ~RI_CURSOR
;
320 vd
->switch_poll_count
= 0;
328 if (SCREEN_IS_VISIBLE(scr
))
329 printf("vcons_switch_screen: already active");
333 if (vd
->currenttype
!= type
) {
334 vcons_set_screentype(vd
, type
);
335 vd
->currenttype
= type
;
343 if (vd
->show_screen_cb
!= NULL
)
344 vd
->show_screen_cb(scr
);
346 if ((scr
->scr_flags
& VCONS_NO_REDRAW
) == 0)
347 vcons_redraw_screen(scr
);
350 vd
->switch_cb(vd
->switch_cb_arg
, 0, 0);
354 vcons_redraw_screen(struct vcons_screen
*scr
)
356 uint16_t *charptr
= scr
->scr_chars
;
357 long *attrptr
= scr
->scr_attrs
;
358 struct rasops_info
*ri
= &scr
->scr_ri
;
362 if (SCREEN_IS_VISIBLE(scr
) && SCREEN_CAN_DRAW(scr
)) {
365 * only clear the screen when RI_FULLCLEAR is set since we're
366 * going to overwrite every single character cell anyway
368 if (ri
->ri_flg
& RI_FULLCLEAR
) {
369 scr
->scr_vd
->eraserows(ri
, 0, ri
->ri_rows
,
373 /* redraw the screen */
374 #ifdef WSDISPLAY_SCROLLSUPPORT
375 offset
= scr
->scr_current_offset
;
379 for (i
= 0; i
< ri
->ri_rows
; i
++) {
380 for (j
= 0; j
< ri
->ri_cols
; j
++) {
382 * no need to use the wrapper function - we
383 * don't change any characters or attributes
384 * and we already made sure the screen we're
385 * working on is visible
387 scr
->scr_vd
->putchar(ri
, i
, j
,
388 charptr
[offset
], attrptr
[offset
]);
392 ri
->ri_flg
&= ~RI_CURSOR
;
393 scr
->scr_vd
->cursor(ri
, 1, ri
->ri_crow
, ri
->ri_ccol
);
399 vcons_ioctl(void *v
, void *vs
, u_long cmd
, void *data
, int flag
,
402 struct vcons_data
*vd
= v
;
406 case WSDISPLAYIO_GETWSCHAR
:
407 error
= vcons_getwschar((struct vcons_screen
*)vs
,
408 (struct wsdisplay_char
*)data
);
411 case WSDISPLAYIO_PUTWSCHAR
:
412 error
= vcons_putwschar((struct vcons_screen
*)vs
,
413 (struct wsdisplay_char
*)data
);
417 if (vd
->ioctl
!= NULL
)
418 error
= (*vd
->ioctl
)(v
, vs
, cmd
, data
, flag
, l
);
420 error
= EPASSTHROUGH
;
427 vcons_alloc_screen(void *v
, const struct wsscreen_descr
*type
, void **cookiep
,
428 int *curxp
, int *curyp
, long *defattrp
)
430 struct vcons_data
*vd
= v
;
431 struct vcons_screen
*scr
;
434 scr
= malloc(sizeof(struct vcons_screen
), M_DEVBUF
, M_WAITOK
| M_ZERO
);
441 scr
->scr_type
= type
;
443 ret
= vcons_init_screen(vd
, scr
, 0, defattrp
);
449 if (vd
->active
== NULL
) {
452 vd
->currenttype
= type
;
456 *curxp
= scr
->scr_ri
.ri_ccol
;
457 *curyp
= scr
->scr_ri
.ri_crow
;
462 vcons_free_screen(void *v
, void *cookie
)
464 struct vcons_data
*vd
= v
;
465 struct vcons_screen
*scr
= cookie
;
468 /* there should be no rasops activity here */
470 LIST_REMOVE(scr
, next
);
472 if ((scr
->scr_flags
& VCONS_SCREEN_IS_STATIC
) == 0) {
473 free(scr
->scr_attrs
, M_DEVBUF
);
477 * maybe we should just restore the old rasops_info methods
478 * and free the character/attribute buffer here?
481 panic("vcons_free_screen: console");
483 printf("vcons_free_screen: console\n");
487 if (vd
->active
== scr
)
492 vcons_show_screen(void *v
, void *cookie
, int waitok
,
493 void (*cb
)(void *, int, int), void *cb_arg
)
495 struct vcons_data
*vd
= v
;
496 struct vcons_screen
*scr
;
499 if (scr
== vd
->active
)
504 vd
->switch_cb_arg
= cb_arg
;
505 #ifdef VCONS_SWITCH_ASYNC
506 wakeup(&vd
->start_drawing
);
510 callout_schedule(&vd
->switch_callout
, 0);
519 /* wrappers for rasops_info methods */
522 vcons_copycols_buffer(void *cookie
, int row
, int srccol
, int dstcol
, int ncols
)
524 struct rasops_info
*ri
= cookie
;
525 struct vcons_screen
*scr
= ri
->ri_hw
;
526 int from
= srccol
+ row
* ri
->ri_cols
;
527 int to
= dstcol
+ row
* ri
->ri_cols
;
529 #ifdef WSDISPLAY_SCROLLSUPPORT
531 offset
= scr
->scr_offset_to_zero
;
533 memmove(&scr
->scr_attrs
[offset
+ to
], &scr
->scr_attrs
[offset
+ from
],
534 ncols
* sizeof(long));
535 memmove(&scr
->scr_chars
[offset
+ to
], &scr
->scr_chars
[offset
+ from
],
536 ncols
* sizeof(uint16_t));
538 memmove(&scr
->scr_attrs
[to
], &scr
->scr_attrs
[from
],
539 ncols
* sizeof(long));
540 memmove(&scr
->scr_chars
[to
], &scr
->scr_chars
[from
],
541 ncols
* sizeof(uint16_t));
546 vcons_copycols(void *cookie
, int row
, int srccol
, int dstcol
, int ncols
)
548 struct rasops_info
*ri
= cookie
;
549 struct vcons_screen
*scr
= ri
->ri_hw
;
551 vcons_copycols_buffer(cookie
, row
, srccol
, dstcol
, ncols
);
554 if (SCREEN_IS_VISIBLE(scr
) && SCREEN_CAN_DRAW(scr
)) {
555 scr
->scr_vd
->copycols(cookie
, row
, srccol
, dstcol
, ncols
);
561 vcons_erasecols_buffer(void *cookie
, int row
, int startcol
, int ncols
, long fillattr
)
563 struct rasops_info
*ri
= cookie
;
564 struct vcons_screen
*scr
= ri
->ri_hw
;
565 int start
= startcol
+ row
* ri
->ri_cols
;
566 int end
= start
+ ncols
, i
;
568 #ifdef WSDISPLAY_SCROLLSUPPORT
570 offset
= scr
->scr_offset_to_zero
;
572 for (i
= start
; i
< end
; i
++) {
573 scr
->scr_attrs
[offset
+ i
] = fillattr
;
574 scr
->scr_chars
[offset
+ i
] = 0x20;
577 for (i
= start
; i
< end
; i
++) {
578 scr
->scr_attrs
[i
] = fillattr
;
579 scr
->scr_chars
[i
] = 0x20;
585 vcons_erasecols(void *cookie
, int row
, int startcol
, int ncols
, long fillattr
)
587 struct rasops_info
*ri
= cookie
;
588 struct vcons_screen
*scr
= ri
->ri_hw
;
590 vcons_erasecols_buffer(cookie
, row
, startcol
, ncols
, fillattr
);
593 if (SCREEN_IS_VISIBLE(scr
) && SCREEN_CAN_DRAW(scr
)) {
594 scr
->scr_vd
->erasecols(cookie
, row
, startcol
, ncols
,
601 vcons_copyrows_buffer(void *cookie
, int srcrow
, int dstrow
, int nrows
)
603 struct rasops_info
*ri
= cookie
;
604 struct vcons_screen
*scr
= ri
->ri_hw
;
607 #ifdef WSDISPLAY_SCROLLSUPPORT
609 offset
= scr
->scr_offset_to_zero
;
611 /* do we need to scroll the back buffer? */
613 from
= ri
->ri_cols
* srcrow
;
614 to
= ri
->ri_cols
* dstrow
;
616 memmove(&scr
->scr_attrs
[to
], &scr
->scr_attrs
[from
],
617 scr
->scr_offset_to_zero
* sizeof(long));
618 memmove(&scr
->scr_chars
[to
], &scr
->scr_chars
[from
],
619 scr
->scr_offset_to_zero
* sizeof(uint16_t));
621 from
= ri
->ri_cols
* srcrow
+ offset
;
622 to
= ri
->ri_cols
* dstrow
+ offset
;
623 len
= ri
->ri_cols
* nrows
;
626 from
= ri
->ri_cols
* srcrow
;
627 to
= ri
->ri_cols
* dstrow
;
628 len
= ri
->ri_cols
* nrows
;
630 memmove(&scr
->scr_attrs
[to
], &scr
->scr_attrs
[from
],
632 memmove(&scr
->scr_chars
[to
], &scr
->scr_chars
[from
],
633 len
* sizeof(uint16_t));
637 vcons_copyrows(void *cookie
, int srcrow
, int dstrow
, int nrows
)
639 struct rasops_info
*ri
= cookie
;
640 struct vcons_screen
*scr
= ri
->ri_hw
;
642 vcons_copyrows_buffer(cookie
, srcrow
, dstrow
, nrows
);
645 if (SCREEN_IS_VISIBLE(scr
) && SCREEN_CAN_DRAW(scr
)) {
646 scr
->scr_vd
->copyrows(cookie
, srcrow
, dstrow
, nrows
);
652 vcons_eraserows_buffer(void *cookie
, int row
, int nrows
, long fillattr
)
654 struct rasops_info
*ri
= cookie
;
655 struct vcons_screen
*scr
= ri
->ri_hw
;
658 #ifdef WSDISPLAY_SCROLLSUPPORT
660 offset
= scr
->scr_offset_to_zero
;
662 start
= ri
->ri_cols
* row
+ offset
;
663 end
= ri
->ri_cols
* (row
+ nrows
) + offset
;
665 start
= ri
->ri_cols
* row
;
666 end
= ri
->ri_cols
* (row
+ nrows
);
669 for (i
= start
; i
< end
; i
++) {
670 scr
->scr_attrs
[i
] = fillattr
;
671 scr
->scr_chars
[i
] = 0x20;
676 vcons_eraserows(void *cookie
, int row
, int nrows
, long fillattr
)
678 struct rasops_info
*ri
= cookie
;
679 struct vcons_screen
*scr
= ri
->ri_hw
;
681 vcons_eraserows_buffer(cookie
, row
, nrows
, fillattr
);
684 if (SCREEN_IS_VISIBLE(scr
) && SCREEN_CAN_DRAW(scr
)) {
685 scr
->scr_vd
->eraserows(cookie
, row
, nrows
, fillattr
);
691 vcons_putchar_buffer(void *cookie
, int row
, int col
, u_int c
, long attr
)
693 struct rasops_info
*ri
= cookie
;
694 struct vcons_screen
*scr
= ri
->ri_hw
;
697 #ifdef WSDISPLAY_SCROLLSUPPORT
699 offset
= scr
->scr_offset_to_zero
;
701 if ((row
>= 0) && (row
< ri
->ri_rows
) && (col
>= 0) &&
702 (col
< ri
->ri_cols
)) {
703 pos
= col
+ row
* ri
->ri_cols
;
704 scr
->scr_attrs
[pos
+ offset
] = attr
;
705 scr
->scr_chars
[pos
+ offset
] = c
;
708 if ((row
>= 0) && (row
< ri
->ri_rows
) && (col
>= 0) &&
709 (col
< ri
->ri_cols
)) {
710 pos
= col
+ row
* ri
->ri_cols
;
711 scr
->scr_attrs
[pos
] = attr
;
712 scr
->scr_chars
[pos
] = c
;
718 vcons_putchar(void *cookie
, int row
, int col
, u_int c
, long attr
)
720 struct rasops_info
*ri
= cookie
;
721 struct vcons_screen
*scr
= ri
->ri_hw
;
723 vcons_putchar_buffer(cookie
, row
, col
, c
, attr
);
726 if (SCREEN_IS_VISIBLE(scr
) && SCREEN_CAN_DRAW(scr
)) {
727 scr
->scr_vd
->putchar(cookie
, row
, col
, c
, attr
);
733 vcons_cursor(void *cookie
, int on
, int row
, int col
)
735 struct rasops_info
*ri
= cookie
;
736 struct vcons_screen
*scr
= ri
->ri_hw
;
739 if (SCREEN_IS_VISIBLE(scr
) && SCREEN_CAN_DRAW(scr
)) {
740 scr
->scr_vd
->cursor(cookie
, on
, row
, col
);
742 scr
->scr_ri
.ri_crow
= row
;
743 scr
->scr_ri
.ri_ccol
= col
;
748 /* methods to read/write characters via ioctl() */
751 vcons_putwschar(struct vcons_screen
*scr
, struct wsdisplay_char
*wsc
)
754 struct rasops_info
*ri
;
756 KASSERT(scr
!= NULL
&& wsc
!= NULL
);
760 if (__predict_false((unsigned int)wsc
->col
> ri
->ri_cols
||
761 (unsigned int)wsc
->row
> ri
->ri_rows
))
764 if ((wsc
->row
>= 0) && (wsc
->row
< ri
->ri_rows
) && (wsc
->col
>= 0) &&
765 (wsc
->col
< ri
->ri_cols
)) {
767 ri
->ri_ops
.allocattr(ri
, wsc
->foreground
, wsc
->background
,
769 vcons_putchar(ri
, wsc
->row
, wsc
->col
, wsc
->letter
, attr
);
771 printf("vcons_putwschar(%d, %d, %x, %lx\n", wsc
->row
, wsc
->col
,
780 vcons_getwschar(struct vcons_screen
*scr
, struct wsdisplay_char
*wsc
)
784 struct rasops_info
*ri
;
786 KASSERT(scr
!= NULL
&& wsc
!= NULL
);
790 if ((wsc
->row
>= 0) && (wsc
->row
< ri
->ri_rows
) && (wsc
->col
>= 0) &&
791 (wsc
->col
< ri
->ri_cols
)) {
793 offset
= ri
->ri_cols
* wsc
->row
+ wsc
->col
;
794 #ifdef WSDISPLAY_SCROLLSUPPORT
795 offset
+= scr
->scr_offset_to_zero
;
797 wsc
->letter
= scr
->scr_chars
[offset
];
798 attr
= scr
->scr_attrs
[offset
];
801 * this is ugly. We need to break up an attribute into colours and
802 * flags but there's no rasops method to do that so we must rely on
803 * the 'canonical' encoding.
806 printf("vcons_getwschar: %d, %d, %x, %lx\n", wsc
->row
,
807 wsc
->col
, wsc
->letter
, attr
);
809 wsc
->foreground
= (attr
>> 24) & 0xff;
810 wsc
->background
= (attr
>> 16) & 0xff;
811 wsc
->flags
= attr
& 0xff;
817 #ifdef WSDISPLAY_SCROLLSUPPORT
820 vcons_scroll(void *cookie
, void *vs
, int where
)
822 struct vcons_screen
*scr
= vs
;
825 scr
->scr_line_wanted
= 0;
827 scr
->scr_line_wanted
= scr
->scr_line_wanted
- where
;
828 if (scr
->scr_line_wanted
< 0)
829 scr
->scr_line_wanted
= 0;
830 if (scr
->scr_line_wanted
> scr
->scr_lines_in_buffer
)
831 scr
->scr_line_wanted
= scr
->scr_lines_in_buffer
;
834 if (scr
->scr_line_wanted
!= scr
->scr_current_line
) {
836 vcons_do_scroll(scr
);
841 vcons_do_scroll(struct vcons_screen
*scr
)
843 int dist
, from
, to
, num
;
844 int r_offset
, r_start
;
847 if (scr
->scr_line_wanted
== scr
->scr_current_line
)
849 dist
= scr
->scr_line_wanted
- scr
->scr_current_line
;
850 scr
->scr_current_line
= scr
->scr_line_wanted
;
851 scr
->scr_current_offset
= scr
->scr_ri
.ri_cols
*
852 (scr
->scr_lines_in_buffer
- scr
->scr_current_line
);
853 if (abs(dist
) >= scr
->scr_ri
.ri_rows
) {
854 vcons_redraw_screen(scr
);
857 /* scroll and redraw only what we really have to */
862 num
= scr
->scr_ri
.ri_rows
- dist
;
863 /* now the redraw parameters */
864 r_offset
= scr
->scr_current_offset
;
870 num
= scr
->scr_ri
.ri_rows
+ dist
;
871 r_offset
= scr
->scr_current_offset
+ num
* scr
->scr_ri
.ri_cols
;
874 scr
->scr_vd
->copyrows(scr
, from
, to
, num
);
875 for (i
= 0; i
< abs(dist
); i
++) {
876 for (j
= 0; j
< scr
->scr_ri
.ri_cols
; j
++) {
877 scr
->scr_vd
->putchar(scr
, i
+ r_start
, j
,
878 scr
->scr_chars
[r_offset
],
879 scr
->scr_attrs
[r_offset
]);
884 if (scr
->scr_line_wanted
== 0) {
885 /* this was a reset - need to draw the cursor */
886 scr
->scr_ri
.ri_flg
&= ~RI_CURSOR
;
887 scr
->scr_vd
->cursor(scr
, 1, scr
->scr_ri
.ri_crow
,
888 scr
->scr_ri
.ri_ccol
);
892 #endif /* WSDISPLAY_SCROLLSUPPORT */
894 /* async drawing using a kernel thread */
896 #ifdef VCONS_SWITCH_ASYNC
898 vcons_kthread(void *cookie
)
900 struct vcons_data
*vd
= cookie
;
901 struct vcons_screen
*scr
;
906 tsleep(&vd
->start_drawing
, 0, "vc_idle", sec
);
907 if ((vd
->wanted
!= vd
->active
) && (vd
->wanted
!= NULL
)) {
909 * we need to switch screens
910 * so first we mark the active screen as invisible
911 * and wait until it's idle
914 SCREEN_INVISIBLE(vd
->active
);
915 while (SCREEN_IS_BUSY(vd
->active
)) {
917 tsleep(&vd
->done_drawing
, 0, "vc_wait", sec
);
920 * now we mark the wanted screen busy so nobody
921 * messes around while we redraw it
927 if (vd
->show_screen_cb
!= NULL
)
928 vd
->show_screen_cb(scr
);
930 if ((scr
->scr_flags
& VCONS_NO_REDRAW
) == 0)
931 vcons_redraw_screen(scr
);
934 vd
->switch_cb(vd
->switch_cb_arg
, 0, 0);
938 #endif /* VCONS_SWITCH_ASYNC */