148187Skato/*-
248516Skato * Copyright (c) 1999 FreeBSD(98) Porting Team.
348516Skato * All rights reserved.
448516Skato *
548516Skato * Redistribution and use in source and binary forms, with or without
648516Skato * modification, are permitted provided that the following conditions
748516Skato * are met:
848516Skato * 1. Redistributions of source code must retain the above copyright
948516Skato *    notice, this list of conditions and the following disclaimer as
1048516Skato *    the first lines of this file unmodified.
1148516Skato * 2. Redistributions in binary form must reproduce the above copyright
1248516Skato *    notice, this list of conditions and the following disclaimer in the
1348516Skato *    documentation and/or other materials provided with the distribution.
1448516Skato *
1548516Skato * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1648516Skato * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1748516Skato * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1848516Skato * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1948516Skato * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2048516Skato * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2148516Skato * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2248516Skato * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2348516Skato * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2448516Skato * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2548516Skato *
2650477Speter * $FreeBSD$
2748187Skato */
2848187Skato
2948187Skato#include "opt_syscons.h"
3048187Skato
3148187Skato#include <sys/param.h>
3248187Skato#include <sys/systm.h>
3348187Skato#include <sys/malloc.h>
3466870Skato#include <sys/consio.h>
3566870Skato#include <sys/fbio.h>
3648187Skato
3748187Skato#include <machine/md_var.h>
3848187Skato
3948187Skato#include <dev/fb/fbreg.h>
4048187Skato#include <dev/syscons/syscons.h>
4148187Skato
4280371Snyan#define ATTR_OFFSET_FB		0x2000
4380371Snyan#define attr_offset(vtb)	((vtb)->vtb_size*sizeof(u_int16_t))
4448187Skato
4580371Snyan#define vtb_pointer(vtb, at)					\
4680371Snyan    ((vtb)->vtb_buffer + sizeof(u_int16_t)*(at))
4780371Snyan
4848187Skato#define vtb_wrap(vtb, at, offset)				\
4948187Skato    (((at) + (offset) + (vtb)->vtb_size)%(vtb)->vtb_size)
5048187Skato
5180371Snyanstatic u_int8_t	ibmpc_to_pc98[256] = {
5280371Snyan	0x01, 0x21, 0x81, 0xa1, 0x41, 0x61, 0xc1, 0xe1,
5380371Snyan	0x09, 0x29, 0x89, 0xa9, 0x49, 0x69, 0xc9, 0xe9,
5480371Snyan	0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
5580371Snyan	0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
5680371Snyan	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
5780371Snyan	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
5880371Snyan	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
5980371Snyan	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
6080371Snyan	0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
6180371Snyan	0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
6280371Snyan	0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
6380371Snyan	0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
6480371Snyan	0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
6580371Snyan	0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
6680371Snyan	0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
6780371Snyan	0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
6848187Skato
6980371Snyan	0x03, 0x23, 0x83, 0xa3, 0x43, 0x63, 0xc3, 0xe3,
7080371Snyan	0x0b, 0x2b, 0x8b, 0xab, 0x4b, 0x6b, 0xcb, 0xeb,
7180371Snyan	0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
7280371Snyan	0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
7380371Snyan	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
7480371Snyan	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
7580371Snyan	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
7680371Snyan	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
7780371Snyan	0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
7880371Snyan	0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
7980371Snyan	0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
8080371Snyan	0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
8180371Snyan	0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
8280371Snyan	0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
8380371Snyan	0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
8480371Snyan	0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
8580371Snyan};
8680371Snyan#define	at2pc98(attr)	((attr) | ibmpc_to_pc98[(unsigned)(attr) >> 8])
8748187Skato
8848187Skatovoid
8948187Skatosc_vtb_init(sc_vtb_t *vtb, int type, int cols, int rows, void *buf, int wait)
9048187Skato{
9148187Skato	vtb->vtb_flags = 0;
9248187Skato	vtb->vtb_type = type;
9348187Skato	vtb->vtb_cols = cols;
9448187Skato	vtb->vtb_rows = rows;
9548187Skato	vtb->vtb_size = cols*rows;
96102265Snyan	vtb->vtb_buffer = 0;
9748187Skato	vtb->vtb_tail = 0;
9848187Skato
9948187Skato	switch (type) {
10048187Skato	case VTB_MEMORY:
10148187Skato	case VTB_RINGBUFFER:
10248187Skato		if ((buf == NULL) && (cols*rows != 0)) {
10348187Skato			vtb->vtb_buffer =
10480371Snyan			    (vm_offset_t)malloc(cols*rows*sizeof(u_int16_t)*2,
10580371Snyan				M_DEVBUF,
106111119Simp				((wait) ? M_WAITOK : M_NOWAIT) | M_ZERO);
107102265Snyan			if (vtb->vtb_buffer != 0) {
10879702Snyan				vtb->vtb_flags |= VTB_ALLOCED;
10948187Skato			}
11048187Skato		} else {
11148187Skato			vtb->vtb_buffer = (vm_offset_t)buf;
11248187Skato		}
11348187Skato		vtb->vtb_flags |= VTB_VALID;
11448187Skato		break;
11548187Skato	case VTB_FRAMEBUFFER:
11648187Skato		vtb->vtb_buffer = (vm_offset_t)buf;
11748187Skato		vtb->vtb_flags |= VTB_VALID;
11848187Skato		break;
11948187Skato	default:
12048187Skato		break;
12148187Skato	}
12248187Skato}
12348187Skato
12448187Skatovoid
12548187Skatosc_vtb_destroy(sc_vtb_t *vtb)
12648187Skato{
12748187Skato	vm_offset_t p;
12848187Skato
12948187Skato	vtb->vtb_cols = 0;
13048187Skato	vtb->vtb_rows = 0;
13148187Skato	vtb->vtb_size = 0;
13248187Skato	vtb->vtb_tail = 0;
13348187Skato
13448187Skato	p = vtb->vtb_buffer;
135102265Snyan	vtb->vtb_buffer = 0;
13648187Skato	switch (vtb->vtb_type) {
13748187Skato	case VTB_MEMORY:
13848187Skato	case VTB_RINGBUFFER:
139102265Snyan		if ((vtb->vtb_flags & VTB_ALLOCED) && (p != 0))
14048187Skato			free((void *)p, M_DEVBUF);
14148187Skato		break;
14248187Skato	default:
14348187Skato		break;
14448187Skato	}
14579702Snyan	vtb->vtb_flags = 0;
14648187Skato	vtb->vtb_type = VTB_INVALID;
14748187Skato}
14848187Skato
14948187Skatosize_t
15048187Skatosc_vtb_size(int cols, int rows)
15148187Skato{
15248187Skato	return (size_t)(cols*rows*sizeof(u_int16_t)*2);
15348187Skato}
15448187Skato
15548187Skatoint
15648187Skatosc_vtb_getc(sc_vtb_t *vtb, int at)
15748187Skato{
15880371Snyan	vm_offset_t p = vtb_pointer(vtb, at);
15980371Snyan
16048187Skato	if (vtb->vtb_type == VTB_FRAMEBUFFER)
16180371Snyan		return (readw(p) & 0x00ff);
16248187Skato	else
16380371Snyan		return (*(u_int16_t *)p & 0x00ff);
16448187Skato}
16548187Skato
16648187Skatoint
16748187Skatosc_vtb_geta(sc_vtb_t *vtb, int at)
16848187Skato{
16980371Snyan	vm_offset_t p = vtb_pointer(vtb, at);
17080371Snyan
17148187Skato	if (vtb->vtb_type == VTB_FRAMEBUFFER)
17287886Snyan		return (readw(p + ATTR_OFFSET_FB) & 0xff00);
17348187Skato	else
17487886Snyan		return (*(u_int16_t *)(p + attr_offset(vtb)) & 0xff00);
17548187Skato}
17648187Skato
177228471Sedstatic inline void
17880371Snyanvtb_putc(sc_vtb_t *vtb, vm_offset_t p, int c, int a)
17948187Skato{
18048187Skato	if (vtb->vtb_type == VTB_FRAMEBUFFER) {
18180371Snyan		writew(p, c);
18280371Snyan		writew(p + ATTR_OFFSET_FB, at2pc98(a));
18348187Skato	} else {
18480371Snyan		*(u_int16_t *)p = c;
18580371Snyan		*(u_int16_t *)(p + attr_offset(vtb)) = at2pc98(a);
18648187Skato	}
18748187Skato}
18848187Skato
18980371Snyanvoid
19080371Snyansc_vtb_putc(sc_vtb_t *vtb, int at, int c, int a)
19180371Snyan{
19280371Snyan	vtb_putc(vtb, vtb_pointer(vtb, at), c, a);
19380371Snyan}
19480371Snyan
19548187Skatovm_offset_t
19648187Skatosc_vtb_putchar(sc_vtb_t *vtb, vm_offset_t p, int c, int a)
19748187Skato{
19880371Snyan	vtb_putc(vtb, p, c, a);
19948187Skato	return (p + sizeof(u_int16_t));
20048187Skato}
20148187Skato
20248187Skatovm_offset_t
20348187Skatosc_vtb_pointer(sc_vtb_t *vtb, int at)
20448187Skato{
20580371Snyan	return (vtb_pointer(vtb, at));
20648187Skato}
20748187Skato
20848187Skatoint
20948187Skatosc_vtb_pos(sc_vtb_t *vtb, int pos, int offset)
21048187Skato{
21148187Skato	return ((pos + offset + vtb->vtb_size)%vtb->vtb_size);
21248187Skato}
21348187Skato
21448187Skatovoid
21548187Skatosc_vtb_clear(sc_vtb_t *vtb, int c, int attr)
21648187Skato{
21780371Snyan	vm_offset_t p = vtb_pointer(vtb, 0);
21880371Snyan
21948187Skato	if (vtb->vtb_type == VTB_FRAMEBUFFER) {
22080371Snyan		fillw_io(c, p, vtb->vtb_size);
22180371Snyan		fillw_io(at2pc98(attr), p + ATTR_OFFSET_FB, vtb->vtb_size);
22248187Skato	} else {
22380371Snyan		fillw(c, (void *)p, vtb->vtb_size);
22480371Snyan		fillw(at2pc98(attr), (void *)(p + attr_offset(vtb)),
22580371Snyan		      vtb->vtb_size);
22648187Skato	}
22748187Skato}
22848187Skato
22948187Skatovoid
23048187Skatosc_vtb_copy(sc_vtb_t *vtb1, int from, sc_vtb_t *vtb2, int to, int count)
23148187Skato{
23280371Snyan	vm_offset_t p1, p2;
23380371Snyan
23480371Snyan	p1 = vtb_pointer(vtb1, from);
23580371Snyan	p2 = vtb_pointer(vtb2, to);
23648187Skato	if (vtb2->vtb_type == VTB_FRAMEBUFFER) {
23780371Snyan		bcopy_toio(p1, p2, count*sizeof(u_int16_t));
23880371Snyan		bcopy_toio(p1 + attr_offset(vtb1),
23980371Snyan			   p2 + ATTR_OFFSET_FB,
24048187Skato			   count*sizeof(u_int16_t));
24148187Skato	} else if (vtb1->vtb_type == VTB_FRAMEBUFFER) {
24280371Snyan		bcopy_fromio(p1, p2, count*sizeof(u_int16_t));
24380371Snyan		bcopy_fromio(p1 + ATTR_OFFSET_FB,
24480371Snyan			     p2 + attr_offset(vtb2),
24548187Skato			     count*sizeof(u_int16_t));
24648187Skato	} else {
24780371Snyan		bcopy((void *)p1, (void *)p2, count*sizeof(u_int16_t));
24880371Snyan		bcopy((void *)(p1 + attr_offset(vtb1)),
24980371Snyan		      (void *)(p2 + attr_offset(vtb2)),
25048187Skato		      count*sizeof(u_int16_t));
25148187Skato	}
25248187Skato}
25348187Skato
25448187Skatovoid
25548187Skatosc_vtb_append(sc_vtb_t *vtb1, int from, sc_vtb_t *vtb2, int count)
25648187Skato{
25748187Skato	int len;
25880371Snyan	vm_offset_t p1, p2;
25948187Skato
26048187Skato	if (vtb2->vtb_type != VTB_RINGBUFFER)
26148187Skato		return;
26248187Skato
26348187Skato	while (count > 0) {
26480371Snyan		p1 = vtb_pointer(vtb1, from);
26580371Snyan		p2 = vtb_pointer(vtb2, vtb2->vtb_tail);
26648187Skato		len = imin(count, vtb2->vtb_size - vtb2->vtb_tail);
26748187Skato		if (vtb1->vtb_type == VTB_FRAMEBUFFER) {
26880371Snyan			bcopy_fromio(p1, p2, len*sizeof(u_int16_t));
26980371Snyan			bcopy_fromio(p1 + ATTR_OFFSET_FB,
27080371Snyan				     p2 + attr_offset(vtb2),
27148187Skato				     len*sizeof(u_int16_t));
27248187Skato		} else {
27380371Snyan			bcopy((void *)p1, (void *)p2, len*sizeof(u_int16_t));
27480371Snyan			bcopy((void *)(p1 + attr_offset(vtb1)),
27580371Snyan			      (void *)(p2 + attr_offset(vtb2)),
27648187Skato			      len*sizeof(u_int16_t));
27748187Skato		}
27848187Skato		from += len;
27948187Skato		count -= len;
28048187Skato		vtb2->vtb_tail = vtb_wrap(vtb2, vtb2->vtb_tail, len);
28148187Skato	}
28248187Skato}
28348187Skato
28448187Skatovoid
28548187Skatosc_vtb_seek(sc_vtb_t *vtb, int pos)
28648187Skato{
28748187Skato	vtb->vtb_tail = pos%vtb->vtb_size;
28848187Skato}
28948187Skato
29048187Skatovoid
29148187Skatosc_vtb_erase(sc_vtb_t *vtb, int at, int count, int c, int attr)
29248187Skato{
29380371Snyan	vm_offset_t p;
29480371Snyan
29548187Skato	if (at + count > vtb->vtb_size)
29648187Skato		count = vtb->vtb_size - at;
29780371Snyan	p = vtb_pointer(vtb, at);
29848187Skato	if (vtb->vtb_type == VTB_FRAMEBUFFER) {
29980371Snyan		fillw_io(c, p, count);
30080371Snyan		fillw_io(at2pc98(attr), p + ATTR_OFFSET_FB, count);
30148187Skato	} else {
30280371Snyan		fillw(c, (void *)p, count);
30380371Snyan		fillw(at2pc98(attr), (void *)(p + attr_offset(vtb)), count);
30448187Skato	}
30548187Skato}
30648187Skato
30748187Skatovoid
30848190Skatosc_vtb_move(sc_vtb_t *vtb, int from, int to, int count)
30948190Skato{
31080371Snyan	vm_offset_t p1, p2;
31180371Snyan
31248190Skato	if (from + count > vtb->vtb_size)
31348190Skato		count = vtb->vtb_size - from;
31448190Skato	if (to + count > vtb->vtb_size)
31548190Skato		count = vtb->vtb_size - to;
31648190Skato	if (count <= 0)
31748190Skato		return;
31880371Snyan
31980371Snyan	p1 = vtb_pointer(vtb, from);
32080371Snyan	p2 = vtb_pointer(vtb, to);
32148190Skato	if (vtb->vtb_type == VTB_FRAMEBUFFER) {
32280371Snyan		bcopy_io(p1, p2, count*sizeof(u_int16_t));
32380371Snyan		bcopy_io(p1 + ATTR_OFFSET_FB,
32480371Snyan			 p2 + ATTR_OFFSET_FB, count*sizeof(u_int16_t));
32548190Skato	} else {
32680371Snyan		bcopy((void *)p1, (void *)p2, count*sizeof(u_int16_t));
32780371Snyan		bcopy((void *)(p1 + attr_offset(vtb)),
32880371Snyan		      (void *)(p2 + attr_offset(vtb)), count*sizeof(u_int16_t));
32948190Skato	}
33048190Skato}
33148190Skato
33248190Skatovoid
33348187Skatosc_vtb_delete(sc_vtb_t *vtb, int at, int count, int c, int attr)
33448187Skato{
33548187Skato	int len;
33680371Snyan	vm_offset_t p1, p2;
33748187Skato
33848187Skato	if (at + count > vtb->vtb_size)
33948187Skato		count = vtb->vtb_size - at;
34048187Skato	len = vtb->vtb_size - at - count;
34148187Skato	if (len > 0) {
34280371Snyan		p1 = vtb_pointer(vtb, at + count);
34380371Snyan		p2 = vtb_pointer(vtb, at);
34448187Skato		if (vtb->vtb_type == VTB_FRAMEBUFFER) {
34580371Snyan			bcopy_io(p1, p2, len*sizeof(u_int16_t));
34680371Snyan			bcopy_io(p1 + ATTR_OFFSET_FB,
34780371Snyan				 p2 + ATTR_OFFSET_FB,
34848187Skato				 len*sizeof(u_int16_t));
34948187Skato		} else {
35080371Snyan			bcopy((void *)p1, (void *)p2, len*sizeof(u_int16_t));
35180371Snyan			bcopy((void *)(p1 + attr_offset(vtb)),
35280371Snyan			      (void *)(p2 + attr_offset(vtb)),
35348187Skato			      len*sizeof(u_int16_t));
35448187Skato		}
35548187Skato	}
35680371Snyan	p1 = vtb_pointer(vtb, at + len);
35748187Skato	if (vtb->vtb_type == VTB_FRAMEBUFFER) {
35880371Snyan		fillw_io(c, p1, vtb->vtb_size - at - len);
35980371Snyan		fillw_io(at2pc98(attr), p1 + ATTR_OFFSET_FB,
36048187Skato			 vtb->vtb_size - at - len);
36148187Skato	} else {
36280371Snyan		fillw(c, (void *)p1, vtb->vtb_size - at - len);
36380371Snyan		fillw(at2pc98(attr), (void *)(p1 + attr_offset(vtb)),
36448187Skato		      vtb->vtb_size - at - len);
36548187Skato	}
36648187Skato}
36748187Skato
36848187Skatovoid
36948187Skatosc_vtb_ins(sc_vtb_t *vtb, int at, int count, int c, int attr)
37048187Skato{
37180371Snyan	vm_offset_t p1, p2;
37280371Snyan
37380371Snyan	p1 = vtb_pointer(vtb, at);
37448187Skato	if (at + count > vtb->vtb_size) {
37548187Skato		count = vtb->vtb_size - at;
37648187Skato	} else {
37780371Snyan		p2 = vtb_pointer(vtb, at + count);
37848187Skato		if (vtb->vtb_type == VTB_FRAMEBUFFER) {
37980371Snyan			bcopy_io(p1, p2,
38048187Skato				 (vtb->vtb_size - at - count)*sizeof(u_int16_t));
38180371Snyan			bcopy_io(p1 + ATTR_OFFSET_FB,
38280371Snyan				 p2 + ATTR_OFFSET_FB,
38348187Skato				 (vtb->vtb_size - at - count)*sizeof(u_int16_t));
38448187Skato		} else {
38580371Snyan			bcopy((void *)p1, (void *)p2,
38648187Skato			      (vtb->vtb_size - at - count)*sizeof(u_int16_t));
38780371Snyan			bcopy((void *)(p1 + attr_offset(vtb)),
38880371Snyan			      (void *)(p2 + attr_offset(vtb)),
38948187Skato			      (vtb->vtb_size - at - count)*sizeof(u_int16_t));
39048187Skato		}
39148187Skato	}
39248187Skato	if (vtb->vtb_type == VTB_FRAMEBUFFER) {
39380371Snyan		fillw_io(c, p1, count);
39480371Snyan		fillw_io(at2pc98(attr), p1 + ATTR_OFFSET_FB, count);
39548187Skato	} else {
39680371Snyan		fillw(c, (void *)p1, count);
39780371Snyan		fillw(at2pc98(attr), (void *)(p1 + attr_offset(vtb)), count);
39848187Skato	}
39948187Skato}
400