#include "opt_syscons.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <machine/console.h>
#include <machine/cpufunc.h>
#include <machine/md_var.h>
#include <dev/video/fb/fbreg.h>
#include "syscons.h"
#define vtb_wrap(vtb, at, offset) \
(((at) + (offset) + (vtb)->vtb_size)%(vtb)->vtb_size)
static
void
sc_vtb_bcopy(void *s, void *d, size_t bytes)
{
size_t count;
size_t n;
uint16_t *sw = s;
uint16_t *dw = d;
count = bytes >> 1;
if (s < d) {
if (bytes & 1)
*(uint8_t *)(dw + count) = *(uint8_t *)(sw + count);
while (count--) {
dw[count] = sw[count];
}
} else {
for (n = 0; n < count; ++n)
dw[n] = sw[n];
if (bytes & 1) {
*(uint8_t *)(dw + n) = *(uint8_t *)(sw + n);
}
}
}
void
sc_vtb_init(sc_vtb_t *vtb, int type, int cols, int rows, void *buf, int wait)
{
vtb->vtb_flags = 0;
vtb->vtb_type = type;
vtb->vtb_cols = cols;
vtb->vtb_rows = rows;
vtb->vtb_size = cols*rows;
vtb->vtb_buffer = NULL;
vtb->vtb_tail = 0;
switch (type) {
case VTB_MEMORY:
case VTB_RINGBUFFER:
if ((buf == NULL) && (cols*rows != 0)) {
vtb->vtb_buffer = kmalloc(cols*rows*sizeof(uint16_t),
M_SYSCONS,
M_ZERO | ((wait) ? M_WAITOK : M_NOWAIT));
if (vtb->vtb_buffer != NULL) {
vtb->vtb_flags |= VTB_VALID;
vtb->vtb_flags |= VTB_ALLOCED;
}
} else {
vtb->vtb_buffer = buf;
vtb->vtb_flags |= VTB_VALID;
}
break;
case VTB_FRAMEBUFFER:
vtb->vtb_buffer = buf;
vtb->vtb_flags |= VTB_VALID;
break;
default:
break;
}
}
void
sc_vtb_destroy(sc_vtb_t *vtb)
{
uint16_t *p;
vtb->vtb_cols = 0;
vtb->vtb_rows = 0;
vtb->vtb_size = 0;
vtb->vtb_tail = 0;
p = vtb->vtb_buffer;
vtb->vtb_buffer = NULL;
switch (vtb->vtb_type) {
case VTB_MEMORY:
case VTB_RINGBUFFER:
if ((vtb->vtb_flags & VTB_ALLOCED) && (p != NULL))
kfree(p, M_SYSCONS);
break;
default:
break;
}
vtb->vtb_flags = 0;
vtb->vtb_type = VTB_INVALID;
}
size_t
sc_vtb_size(int cols, int rows)
{
return (size_t)(cols*rows*sizeof(uint16_t));
}
int
sc_vtb_getc(sc_vtb_t *vtb, int at)
{
if (vtb->vtb_type == VTB_FRAMEBUFFER)
return (readw(vtb->vtb_buffer + at) & 0x00ff);
else
return (*(vtb->vtb_buffer + at) & 0x00ff);
}
int
sc_vtb_geta(sc_vtb_t *vtb, int at)
{
if (vtb->vtb_type == VTB_FRAMEBUFFER)
return (readw(vtb->vtb_buffer + at) & 0xff00);
else
return (*(vtb->vtb_buffer + at) & 0xff00);
}
void
sc_vtb_putc(sc_vtb_t *vtb, int at, int c, int a)
{
if (vtb->vtb_type == VTB_FRAMEBUFFER)
writew(vtb->vtb_buffer + at, a | c);
else
*(vtb->vtb_buffer + at) = a | c;
}
uint16_t *
sc_vtb_putchar(sc_vtb_t *vtb, uint16_t *p, int c, int a)
{
if (vtb->vtb_type == VTB_FRAMEBUFFER)
writew(p, a | c);
else
*p = a | c;
return (p + 1);
}
int
sc_vtb_pos(sc_vtb_t *vtb, int pos, int offset)
{
return ((pos + offset + vtb->vtb_size)%vtb->vtb_size);
}
void
sc_vtb_clear(sc_vtb_t *vtb, int c, int attr)
{
if (vtb->vtb_type == VTB_FRAMEBUFFER)
fillw_io(attr | c, vtb->vtb_buffer, vtb->vtb_size);
else
fillw(attr | c, vtb->vtb_buffer, vtb->vtb_size);
}
void
sc_vtb_copy(sc_vtb_t *vtb1, int from, sc_vtb_t *vtb2, int to, int count)
{
if (vtb2->vtb_type == VTB_FRAMEBUFFER) {
sc_vtb_bcopy(vtb1->vtb_buffer + from, vtb2->vtb_buffer + to,
count*sizeof(uint16_t));
} else if (vtb1->vtb_type == VTB_FRAMEBUFFER) {
sc_vtb_bcopy(vtb1->vtb_buffer + from, vtb2->vtb_buffer + to,
count*sizeof(uint16_t));
} else {
sc_vtb_bcopy(vtb1->vtb_buffer + from, vtb2->vtb_buffer + to,
count*sizeof(uint16_t));
}
}
void
sc_vtb_append(sc_vtb_t *vtb1, int from, sc_vtb_t *vtb2, int count)
{
int len;
if (vtb2->vtb_type != VTB_RINGBUFFER)
return;
while (count > 0) {
len = imin(count, vtb2->vtb_size - vtb2->vtb_tail);
if (vtb1->vtb_type == VTB_FRAMEBUFFER) {
sc_vtb_bcopy(vtb1->vtb_buffer + from,
vtb2->vtb_buffer + vtb2->vtb_tail,
len*sizeof(uint16_t));
} else {
sc_vtb_bcopy(vtb1->vtb_buffer + from,
vtb2->vtb_buffer + vtb2->vtb_tail,
len*sizeof(uint16_t));
}
from += len;
count -= len;
vtb2->vtb_tail = vtb_wrap(vtb2, vtb2->vtb_tail, len);
}
}
void
sc_vtb_seek(sc_vtb_t *vtb, int pos)
{
vtb->vtb_tail = pos%vtb->vtb_size;
}
void
sc_vtb_erase(sc_vtb_t *vtb, int at, int count, int c, int attr)
{
if (at + count > vtb->vtb_size)
count = vtb->vtb_size - at;
if (vtb->vtb_type == VTB_FRAMEBUFFER)
fillw_io(attr | c, vtb->vtb_buffer + at, count);
else
fillw(attr | c, vtb->vtb_buffer + at, count);
}
void
sc_vtb_move(sc_vtb_t *vtb, int from, int to, int count)
{
if (from + count > vtb->vtb_size)
count = vtb->vtb_size - from;
if (to + count > vtb->vtb_size)
count = vtb->vtb_size - to;
if (count <= 0)
return;
if (vtb->vtb_type == VTB_FRAMEBUFFER) {
sc_vtb_bcopy(vtb->vtb_buffer + from, vtb->vtb_buffer + to,
count*sizeof(uint16_t));
} else {
sc_vtb_bcopy(vtb->vtb_buffer + from, vtb->vtb_buffer + to,
count*sizeof(uint16_t));
}
}
void
sc_vtb_delete(sc_vtb_t *vtb, int at, int count, int c, int attr)
{
int len;
if (at + count > vtb->vtb_size)
count = vtb->vtb_size - at;
len = vtb->vtb_size - at - count;
if (len > 0) {
if (vtb->vtb_type == VTB_FRAMEBUFFER) {
sc_vtb_bcopy(vtb->vtb_buffer + at + count,
vtb->vtb_buffer + at,
len*sizeof(uint16_t));
} else {
sc_vtb_bcopy(vtb->vtb_buffer + at + count,
vtb->vtb_buffer + at,
len*sizeof(uint16_t));
}
}
if (vtb->vtb_type == VTB_FRAMEBUFFER)
fillw_io(attr | c, vtb->vtb_buffer + at + len,
vtb->vtb_size - at - len);
else
fillw(attr | c, vtb->vtb_buffer + at + len,
vtb->vtb_size - at - len);
}
void
sc_vtb_ins(sc_vtb_t *vtb, int at, int count, int c, int attr)
{
if (at + count > vtb->vtb_size) {
count = vtb->vtb_size - at;
} else {
if (vtb->vtb_type == VTB_FRAMEBUFFER) {
sc_vtb_bcopy(vtb->vtb_buffer + at,
vtb->vtb_buffer + at + count,
(vtb->vtb_size - at - count)*sizeof(uint16_t));
} else {
sc_vtb_bcopy(vtb->vtb_buffer + at,
vtb->vtb_buffer + at + count,
(vtb->vtb_size - at - count)*sizeof(uint16_t));
}
}
if (vtb->vtb_type == VTB_FRAMEBUFFER)
fillw_io(attr | c, vtb->vtb_buffer + at, count);
else
fillw(attr | c, vtb->vtb_buffer + at, count);
}