vt_buf.c revision 219888
1219888Sed/*- 2219888Sed * Copyright (c) 2009 The FreeBSD Foundation 3219888Sed * All rights reserved. 4219888Sed * 5219888Sed * This software was developed by Ed Schouten under sponsorship from the 6219888Sed * FreeBSD Foundation. 7219888Sed * 8219888Sed * Redistribution and use in source and binary forms, with or without 9219888Sed * modification, are permitted provided that the following conditions 10219888Sed * are met: 11219888Sed * 1. Redistributions of source code must retain the above copyright 12219888Sed * notice, this list of conditions and the following disclaimer. 13219888Sed * 2. Redistributions in binary form must reproduce the above copyright 14219888Sed * notice, this list of conditions and the following disclaimer in the 15219888Sed * documentation and/or other materials provided with the distribution. 16219888Sed * 17219888Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219888Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219888Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219888Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219888Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219888Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219888Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219888Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219888Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219888Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219888Sed * SUCH DAMAGE. 28219888Sed */ 29219888Sed 30219888Sed#include <sys/cdefs.h> 31219888Sed__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/vt/vt_buf.c 219888 2011-03-22 21:31:31Z ed $"); 32219888Sed 33219888Sed#include <sys/param.h> 34219888Sed#include <sys/kernel.h> 35219888Sed#include <sys/lock.h> 36219888Sed#include <sys/malloc.h> 37219888Sed#include <sys/mutex.h> 38219888Sed#include <sys/systm.h> 39219888Sed 40219888Sed#include <dev/vt/vt.h> 41219888Sed 42219888Sedstatic MALLOC_DEFINE(M_VTBUF, "vtbuf", "vt buffer"); 43219888Sed 44219888Sed#define VTBUF_LOCK(vb) mtx_lock_spin(&(vb)->vb_lock) 45219888Sed#define VTBUF_UNLOCK(vb) mtx_unlock_spin(&(vb)->vb_lock) 46219888Sed 47219888Sedstatic inline uint64_t 48219888Sedvtbuf_dirty_axis(unsigned int begin, unsigned int end) 49219888Sed{ 50219888Sed uint64_t left, right, mask; 51219888Sed 52219888Sed /* 53219888Sed * Mark all bits between begin % 64 and end % 64 dirty. 54219888Sed * This code is functionally equivalent to: 55219888Sed * 56219888Sed * for (i = begin; i < end; i++) 57219888Sed * mask |= (uint64_t)1 << (i % 64); 58219888Sed */ 59219888Sed 60219888Sed /* Obvious case. Mark everything dirty. */ 61219888Sed if (end - begin >= 64) 62219888Sed return (VBM_DIRTY); 63219888Sed 64219888Sed /* 1....0; used bits on the left. */ 65219888Sed left = VBM_DIRTY << begin % 64; 66219888Sed /* 0....1; used bits on the right. */ 67219888Sed right = VBM_DIRTY >> -end % 64; 68219888Sed 69219888Sed /* 70219888Sed * Only take the intersection. If the result of that is 0, it 71219888Sed * means that the selection crossed a 64 bit boundary along the 72219888Sed * way, which means we have to take the complement. 73219888Sed */ 74219888Sed mask = left & right; 75219888Sed if (mask == 0) 76219888Sed mask = left | right; 77219888Sed return (mask); 78219888Sed} 79219888Sed 80219888Sedstatic inline void 81219888Sedvtbuf_dirty(struct vt_buf *vb, const term_rect_t *area) 82219888Sed{ 83219888Sed 84219888Sed VTBUF_LOCK(vb); 85219888Sed if (vb->vb_dirtyrect.tr_begin.tp_row > area->tr_begin.tp_row) 86219888Sed vb->vb_dirtyrect.tr_begin.tp_row = area->tr_begin.tp_row; 87219888Sed if (vb->vb_dirtyrect.tr_begin.tp_col > area->tr_begin.tp_col) 88219888Sed vb->vb_dirtyrect.tr_begin.tp_col = area->tr_begin.tp_col; 89219888Sed if (vb->vb_dirtyrect.tr_end.tp_row < area->tr_end.tp_row) 90219888Sed vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row; 91219888Sed if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col) 92219888Sed vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col; 93219888Sed vb->vb_dirtymask.vbm_row |= 94219888Sed vtbuf_dirty_axis(area->tr_begin.tp_row, area->tr_end.tp_row); 95219888Sed vb->vb_dirtymask.vbm_col |= 96219888Sed vtbuf_dirty_axis(area->tr_begin.tp_col, area->tr_end.tp_col); 97219888Sed VTBUF_UNLOCK(vb); 98219888Sed} 99219888Sed 100219888Sedstatic inline void 101219888Sedvtbuf_dirty_cell(struct vt_buf *vb, const term_pos_t *p) 102219888Sed{ 103219888Sed term_rect_t area; 104219888Sed 105219888Sed area.tr_begin = *p; 106219888Sed area.tr_end.tp_row = p->tp_row + 1; 107219888Sed area.tr_end.tp_col = p->tp_col + 1; 108219888Sed vtbuf_dirty(vb, &area); 109219888Sed} 110219888Sed 111219888Sedstatic void 112219888Sedvtbuf_make_undirty(struct vt_buf *vb) 113219888Sed{ 114219888Sed 115219888Sed vb->vb_dirtyrect.tr_begin = vb->vb_size; 116219888Sed vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0; 117219888Sed vb->vb_dirtymask.vbm_row = vb->vb_dirtymask.vbm_col = 0; 118219888Sed} 119219888Sed 120219888Sedvoid 121219888Sedvtbuf_undirty(struct vt_buf *vb, term_rect_t *r, struct vt_bufmask *m) 122219888Sed{ 123219888Sed 124219888Sed VTBUF_LOCK(vb); 125219888Sed *r = vb->vb_dirtyrect; 126219888Sed *m = vb->vb_dirtymask; 127219888Sed vtbuf_make_undirty(vb); 128219888Sed VTBUF_UNLOCK(vb); 129219888Sed} 130219888Sed 131219888Sedvoid 132219888Sedvtbuf_copy(struct vt_buf *vb, const term_rect_t *r, const term_pos_t *p2) 133219888Sed{ 134219888Sed const term_pos_t *p1 = &r->tr_begin; 135219888Sed term_rect_t area; 136219888Sed unsigned int rows, cols; 137219888Sed int pr; 138219888Sed 139219888Sed rows = r->tr_end.tp_row - r->tr_begin.tp_row; 140219888Sed cols = r->tr_end.tp_col - r->tr_begin.tp_col; 141219888Sed 142219888Sed /* Handle overlapping copies. */ 143219888Sed if (p2->tp_row < p1->tp_row) { 144219888Sed /* Move data up. */ 145219888Sed for (pr = 0; pr < rows; pr++) 146219888Sed memmove( 147219888Sed &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 148219888Sed &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 149219888Sed cols * sizeof(term_char_t)); 150219888Sed } else { 151219888Sed /* Move data down. */ 152219888Sed for (pr = rows - 1; pr >= 0; pr--) 153219888Sed memmove( 154219888Sed &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 155219888Sed &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 156219888Sed cols * sizeof(term_char_t)); 157219888Sed } 158219888Sed 159219888Sed area.tr_begin = *p2; 160219888Sed area.tr_end.tp_row = p2->tp_row + rows; 161219888Sed area.tr_end.tp_col = p2->tp_col + cols; 162219888Sed vtbuf_dirty(vb, &area); 163219888Sed} 164219888Sed 165219888Sedvoid 166219888Sedvtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 167219888Sed{ 168219888Sed unsigned int pr, pc; 169219888Sed 170219888Sed for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) 171219888Sed for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) 172219888Sed VTBUF_FIELD(vb, pr, pc) = c; 173219888Sed 174219888Sed vtbuf_dirty(vb, r); 175219888Sed} 176219888Sed 177219888Sedvoid 178219888Sedvtbuf_init_early(struct vt_buf *vb) 179219888Sed{ 180219888Sed 181219888Sed vb->vb_flags |= VBF_CURSOR; 182219888Sed vtbuf_make_undirty(vb); 183219888Sed mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN); 184219888Sed} 185219888Sed 186219888Sedvoid 187219888Sedvtbuf_init(struct vt_buf *vb, const term_pos_t *p) 188219888Sed{ 189219888Sed 190219888Sed vb->vb_size = *p; 191219888Sed vb->vb_buffer = malloc(p->tp_row * p->tp_col * sizeof(term_char_t), 192219888Sed M_VTBUF, M_WAITOK); 193219888Sed vtbuf_init_early(vb); 194219888Sed} 195219888Sed 196219888Sedvoid 197219888Sedvtbuf_grow(struct vt_buf *vb, const term_pos_t *p) 198219888Sed{ 199219888Sed term_char_t *old, *new; 200219888Sed 201219888Sed if (p->tp_row > vb->vb_size.tp_row || 202219888Sed p->tp_col > vb->vb_size.tp_col) { 203219888Sed /* Allocate new buffer. */ 204219888Sed new = malloc(p->tp_row * p->tp_col * sizeof(term_char_t), 205219888Sed M_VTBUF, M_WAITOK|M_ZERO); 206219888Sed 207219888Sed /* Toggle it. */ 208219888Sed VTBUF_LOCK(vb); 209219888Sed old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer; 210219888Sed vb->vb_buffer = new; 211219888Sed vb->vb_flags &= ~VBF_STATIC; 212219888Sed vb->vb_size = *p; 213219888Sed vtbuf_make_undirty(vb); 214219888Sed VTBUF_UNLOCK(vb); 215219888Sed 216219888Sed /* Deallocate old buffer. */ 217219888Sed if (old != NULL) 218219888Sed free(old, M_VTBUF); 219219888Sed } 220219888Sed} 221219888Sed 222219888Sedvoid 223219888Sedvtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c) 224219888Sed{ 225219888Sed 226219888Sed if (VTBUF_FIELD(vb, p->tp_row, p->tp_col) != c) { 227219888Sed VTBUF_FIELD(vb, p->tp_row, p->tp_col) = c; 228219888Sed vtbuf_dirty_cell(vb, p); 229219888Sed } 230219888Sed} 231219888Sed 232219888Sedvoid 233219888Sedvtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p) 234219888Sed{ 235219888Sed 236219888Sed if (vb->vb_flags & VBF_CURSOR) { 237219888Sed vtbuf_dirty_cell(vb, &vb->vb_cursor); 238219888Sed vb->vb_cursor = *p; 239219888Sed vtbuf_dirty_cell(vb, &vb->vb_cursor); 240219888Sed } else { 241219888Sed vb->vb_cursor = *p; 242219888Sed } 243219888Sed} 244219888Sed 245219888Sedvoid 246219888Sedvtbuf_cursor_visibility(struct vt_buf *vb, int yes) 247219888Sed{ 248219888Sed int oflags, nflags; 249219888Sed 250219888Sed VTBUF_LOCK(vb); 251219888Sed oflags = vb->vb_flags; 252219888Sed if (yes) 253219888Sed vb->vb_flags |= VBF_CURSOR; 254219888Sed else 255219888Sed vb->vb_flags &= ~VBF_CURSOR; 256219888Sed nflags = vb->vb_flags; 257219888Sed VTBUF_UNLOCK(vb); 258219888Sed 259219888Sed if (oflags != nflags) 260219888Sed vtbuf_dirty_cell(vb, &vb->vb_cursor); 261219888Sed} 262