diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2013-03-25 19:49:09 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2013-03-25 19:49:09 +0000 |
commit | 94dc38214b970534441542d209a713f148f78a94 (patch) | |
tree | 36ed577a73ce771fc4f91bc7d6e858feab6b1da9 /sys/dev | |
parent | e7521828f53f67e25c68dfc644106141ad45c9d2 (diff) |
Add basic support for multiple screens.
ok mpi@, miod@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/rasops/rasops.c | 273 | ||||
-rw-r--r-- | sys/dev/rasops/rasops.h | 27 |
2 files changed, 298 insertions, 2 deletions
diff --git a/sys/dev/rasops/rasops.c b/sys/dev/rasops/rasops.c index 5de50478603..66e473db02e 100644 --- a/sys/dev/rasops/rasops.c +++ b/sys/dev/rasops/rasops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rasops.c,v 1.22 2010/08/28 12:48:14 miod Exp $ */ +/* $OpenBSD: rasops.c,v 1.23 2013/03/25 19:49:08 kettenis Exp $ */ /* $NetBSD: rasops.c,v 1.35 2001/02/02 06:01:01 marcus Exp $ */ /*- @@ -31,8 +31,10 @@ */ #include <sys/param.h> +#include <sys/malloc.h> #include <sys/systm.h> #include <sys/time.h> +#include <sys/workq.h> #include <machine/endian.h> @@ -163,6 +165,17 @@ struct rotatedfont { }; #endif +void rasops_doswitch(void *, void *); +int rasops_vcons_cursor(void *, int, int, int); +int rasops_vcons_mapchar(void *, int, u_int *); +int rasops_vcons_putchar(void *, int, int, u_int, long); +int rasops_vcons_copycols(void *, int, int, int, int); +int rasops_vcons_erasecols(void *, int, int, int, long); +int rasops_vcons_copyrows(void *, int, int, int); +int rasops_vcons_eraserows(void *, int, int, long); +int rasops_vcons_alloc_attr(void *, int, int, int, long *); +void rasops_vcons_unpack_attr(void *, long, int *, int *, int *); + /* * Initialize a 'rasops_info' descriptor. */ @@ -227,6 +240,37 @@ rasops_init(struct rasops_info *ri, int wantrows, int wantcols) if (rasops_reconfig(ri, wantrows, wantcols)) return (-1); + LIST_INIT(&ri->ri_screens); + ri->ri_nscreens = 0; + + ri->ri_putchar = ri->ri_ops.putchar; + ri->ri_copycols = ri->ri_ops.copycols; + ri->ri_erasecols = ri->ri_ops.erasecols; + ri->ri_copyrows = ri->ri_ops.copyrows; + ri->ri_eraserows = ri->ri_ops.eraserows; + ri->ri_alloc_attr = ri->ri_ops.alloc_attr; + + if (ri->ri_flg & RI_VCONS) { + void *cookie; + int curx, cury; + long attr; + + if (rasops_alloc_screen(ri, &cookie, &curx, &cury, &attr)) + return (-1); + + ri->ri_active = cookie; + + ri->ri_ops.cursor = rasops_vcons_cursor; + ri->ri_ops.mapchar = rasops_vcons_mapchar; + ri->ri_ops.putchar = rasops_vcons_putchar; + ri->ri_ops.copycols = rasops_vcons_copycols; + ri->ri_ops.erasecols = rasops_vcons_erasecols; + ri->ri_ops.copyrows = rasops_vcons_copyrows; + ri->ri_ops.eraserows = rasops_vcons_eraserows; + ri->ri_ops.alloc_attr = rasops_vcons_alloc_attr; + ri->ri_ops.unpack_attr = rasops_vcons_unpack_attr; + } + rasops_init_devcmap(ri); return (0); } @@ -1305,3 +1349,230 @@ slow_ovbcopy(void *s, void *d, size_t len) } } #endif /* NRASOPS_BSWAP */ + +struct rasops_screen { + LIST_ENTRY(rasops_screen) rs_next; + struct rasops_info *rs_ri; + + struct wsdisplay_charcell *rs_bs; + int rs_visible; + int rs_crow; + int rs_ccol; +}; + +int +rasops_alloc_screen(void *v, void **cookiep, + int *curxp, int *curyp, long *attrp) +{ + struct rasops_info *ri = v; + struct rasops_screen *scr; + size_t size; + + scr = malloc(sizeof(struct rasops_screen), M_DEVBUF, M_NOWAIT); + if (scr == NULL) + return (ENOMEM); + + size = ri->ri_cols * ri->ri_rows * sizeof(struct wsdisplay_charcell); + scr->rs_bs = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); + if (scr->rs_bs == NULL) { + free(scr, M_DEVBUF); + return (ENOMEM); + } + + *cookiep = scr; + *curxp = 0; + *curyp = 0; + ri->ri_alloc_attr(ri, 0, 0, 0, attrp); + + scr->rs_ri = ri; + scr->rs_visible = (ri->ri_nscreens == 0); + scr->rs_crow = -1; + scr->rs_ccol = -1; + + LIST_INSERT_HEAD(&ri->ri_screens, scr, rs_next); + ri->ri_nscreens++; + + return (0); +} + +void +rasops_free_screen(void *v, void *cookie) +{ + struct rasops_info *ri = v; + struct rasops_screen *scr = cookie; + + LIST_REMOVE(scr, rs_next); + ri->ri_nscreens--; + + free(scr->rs_bs, M_DEVBUF); + free(scr, M_DEVBUF); +} + +int +rasops_show_screen(void *v, void *cookie, int waitok, + void (*cb)(void *, int, int), void *cbarg) +{ + struct rasops_info *ri = v; + + if (cb) { + ri->ri_switchcb = cb; + ri->ri_switchcbarg = cbarg; + workq_queue_task(NULL, &ri->ri_switchwqt, 0, + rasops_doswitch, v, cookie); + return (EAGAIN); + } + + rasops_doswitch(v, cookie); + return (0); +} + +void +rasops_doswitch(void *v, void *cookie) +{ + struct rasops_info *ri = v; + struct rasops_screen *scr = cookie; + int row, col; + long attr; + + rasops_cursor(ri, 0, 0, 0); + ri->ri_active->rs_visible = 0; + ri->ri_alloc_attr(ri, 0, 0, 0, &attr); + ri->ri_eraserows(ri, 0, ri->ri_rows, attr); + ri->ri_active = scr; + ri->ri_active->rs_visible = 1; + for (row = 0; row < ri->ri_rows; row++) { + for (col = 0; col < ri->ri_cols; col++) { + int off = row * scr->rs_ri->ri_cols + col; + + if (scr->rs_bs[off].uc == 0) + continue; + ri->ri_putchar(ri, row, col, scr->rs_bs[off].uc, + scr->rs_bs[off].attr); + } + } + if (scr->rs_crow != -1) + rasops_cursor(ri, 1, scr->rs_crow, scr->rs_ccol); + + if (ri->ri_switchcb) + (*ri->ri_switchcb)(ri->ri_switchcbarg, 0, 0); +} + +int +rasops_vcons_cursor(void *cookie, int on, int row, int col) +{ + struct rasops_screen *scr = cookie; + + scr->rs_crow = on ? row : -1; + scr->rs_ccol = on ? col : -1; + + if (!scr->rs_visible) + return 0; + + return rasops_cursor(scr->rs_ri, on, row, col); +} + +int +rasops_vcons_mapchar(void *cookie, int c, u_int *cp) +{ + struct rasops_screen *scr = cookie; + + return rasops_mapchar(scr->rs_ri, c, cp); +} + +int +rasops_vcons_putchar(void *cookie, int row, int col, u_int uc, long attr) +{ + struct rasops_screen *scr = cookie; + int off = row * scr->rs_ri->ri_cols + col; + + scr->rs_bs[off].uc = uc; + scr->rs_bs[off].attr = attr; + + if (!scr->rs_visible) + return 0; + + return scr->rs_ri->ri_putchar(scr->rs_ri, row, col, uc, attr); +} + +int +rasops_vcons_copycols(void *cookie, int row, int src, int dst, int num) +{ + struct rasops_screen *scr = cookie; + int cols = scr->rs_ri->ri_cols; + + ovbcopy(&scr->rs_bs[row * cols + src], &scr->rs_bs[row * cols + dst], + num * sizeof(struct wsdisplay_charcell)); + + if (!scr->rs_visible) + return 0; + + return scr->rs_ri->ri_copycols(scr->rs_ri, row, src, dst, num); +} + +int +rasops_vcons_erasecols(void *cookie, int row, int col, int num, long attr) +{ + struct rasops_screen *scr = cookie; + int cols = scr->rs_ri->ri_cols; + int i; + + for (i = 0; i < num; i++) { + scr->rs_bs[row * cols + col + i].uc = 0; + scr->rs_bs[row * cols + col + i].attr = attr; + } + + if (!scr->rs_visible) + return 0; + + return scr->rs_ri->ri_erasecols(scr->rs_ri, row, col, num, attr); +} + +int +rasops_vcons_copyrows(void *cookie, int src, int dst, int num) +{ + struct rasops_screen *scr = cookie; + int cols = scr->rs_ri->ri_cols; + + ovbcopy(&scr->rs_bs[src * cols], &scr->rs_bs[dst * cols], + num * cols * sizeof(struct wsdisplay_charcell)); + + if (!scr->rs_visible) + return 0; + + return scr->rs_ri->ri_copyrows(scr->rs_ri, src, dst, num); +} + +int +rasops_vcons_eraserows(void *cookie, int row, int num, long attr) +{ + struct rasops_screen *scr = cookie; + int cols = scr->rs_ri->ri_cols; + int i; + + for (i = 0; i < num * cols; i++) { + scr->rs_bs[row * cols + i].uc = 0; + scr->rs_bs[row * cols + i].attr = attr; + } + + if (!scr->rs_visible) + return 0; + + return scr->rs_ri->ri_eraserows(scr->rs_ri, row, num, attr); +} + +int +rasops_vcons_alloc_attr(void *cookie, int fg, int bg, int flg, long *attr) +{ + struct rasops_screen *scr = cookie; + + return scr->rs_ri->ri_alloc_attr(scr->rs_ri, fg, bg, flg, attr); +} + +void +rasops_vcons_unpack_attr(void *cookie, long attr, int *fg, int *bg, + int *underline) +{ + struct rasops_screen *scr = cookie; + + rasops_unpack_attr(scr->rs_ri, attr, fg, bg, underline); +} diff --git a/sys/dev/rasops/rasops.h b/sys/dev/rasops/rasops.h index 3848ab6f2da..ab0b6b7513c 100644 --- a/sys/dev/rasops/rasops.h +++ b/sys/dev/rasops/rasops.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rasops.h,v 1.10 2009/09/05 14:09:35 miod Exp $ */ +/* $OpenBSD: rasops.h,v 1.11 2013/03/25 19:49:08 kettenis Exp $ */ /* $NetBSD: rasops.h,v 1.13 2000/06/13 13:36:54 ad Exp $ */ /*- @@ -33,6 +33,8 @@ #ifndef _RASOPS_H_ #define _RASOPS_H_ 1 +#include <sys/workq.h> + #ifdef SMALL_KERNEL #define RASOPS_SMALL #endif @@ -52,6 +54,9 @@ struct wsdisplay_font; #define RI_CURSORCLIP 0x0080 /* cursor is currently clipped */ #define RI_ROTATE_CW 0x0100 /* display is rotated, quarter clockwise */ #define RI_CFGDONE 0x0200 /* rasops_reconfig() completed successfully */ +#define RI_VCONS 0x0400 /* virtual consoles */ + +struct rasops_screen; struct rasops_info { /* These must be filled in by the caller */ @@ -112,6 +117,21 @@ struct rasops_info { /* Used to intercept putchar to permit display rotation */ struct wsdisplay_emulops ri_real_ops; #endif + + int ri_nscreens; + LIST_HEAD(, rasops_screen) ri_screens; + struct rasops_screen *ri_active; + + void (*ri_switchcb)(void *, int, int); + void *ri_switchcbarg; + struct workq_task ri_switchwqt; + + int (*ri_putchar)(void *, int, int, u_int, long); + int (*ri_copycols)(void *, int, int, int, int); + int (*ri_erasecols)(void *, int, int, int, long); + int (*ri_copyrows)(void *, int, int, int); + int (*ri_eraserows)(void *, int, int, long); + int (*ri_alloc_attr)(void *, int, int, int, long *); }; #define DELTA(p, d, cast) ((p) = (cast)((caddr_t)(p) + (d))) @@ -148,6 +168,11 @@ int rasops_reconfig(struct rasops_info *, int, int); int rasops_eraserows(void *, int, int, long); int rasops_erasecols(void *, int, int, int, long); +int rasops_alloc_screen(void *, void **, int *, int *, long *); +void rasops_free_screen(void *, void *); +int rasops_show_screen(void *, void *, int, + void (*)(void *, int, int), void *); + extern const u_char rasops_isgray[16]; extern const u_char rasops_cmap[256*3]; |