1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer as
12 *    the first lines of this file unmodified.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#include <sys/cdefs.h>
31#include "opt_syscons.h"
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/malloc.h>
36#include <sys/fbio.h>
37#include <sys/consio.h>
38
39#include <machine/md_var.h>
40#include <machine/bus.h>
41
42#include <dev/fb/fbreg.h>
43#include <dev/syscons/syscons.h>
44
45#define vtb_wrap(vtb, at, offset)				\
46    (((at) + (offset) + (vtb)->vtb_size)%(vtb)->vtb_size)
47
48void
49sc_vtb_init(sc_vtb_t *vtb, int type, int cols, int rows, void *buf, int wait)
50{
51	vtb->vtb_flags = 0;
52	vtb->vtb_type = type;
53	vtb->vtb_cols = cols;
54	vtb->vtb_rows = rows;
55	vtb->vtb_size = cols*rows;
56	vtb->vtb_buffer = 0;
57	vtb->vtb_tail = 0;
58
59	switch (type) {
60	case VTB_MEMORY:
61	case VTB_RINGBUFFER:
62		if ((buf == NULL) && (cols*rows != 0)) {
63			vtb->vtb_buffer =
64				(vm_offset_t)malloc(cols*rows*sizeof(u_int16_t),
65						    M_DEVBUF,
66						    (wait) ? M_WAITOK : M_NOWAIT);
67			if (vtb->vtb_buffer != 0) {
68				bzero((void *)sc_vtb_pointer(vtb, 0),
69				      cols*rows*sizeof(u_int16_t));
70				vtb->vtb_flags |= VTB_ALLOCED;
71			}
72		} else {
73			vtb->vtb_buffer = (vm_offset_t)buf;
74		}
75		vtb->vtb_flags |= VTB_VALID;
76		break;
77	case VTB_FRAMEBUFFER:
78		vtb->vtb_buffer = (vm_offset_t)buf;
79		vtb->vtb_flags |= VTB_VALID;
80		break;
81	default:
82		break;
83	}
84}
85
86void
87sc_vtb_destroy(sc_vtb_t *vtb)
88{
89	vm_offset_t p;
90
91	vtb->vtb_cols = 0;
92	vtb->vtb_rows = 0;
93	vtb->vtb_size = 0;
94	vtb->vtb_tail = 0;
95
96	p = vtb->vtb_buffer;
97	vtb->vtb_buffer = 0;
98	switch (vtb->vtb_type) {
99	case VTB_MEMORY:
100	case VTB_RINGBUFFER:
101		if ((vtb->vtb_flags & VTB_ALLOCED) && (p != 0))
102			free((void *)p, M_DEVBUF);
103		break;
104	default:
105		break;
106	}
107	vtb->vtb_flags = 0;
108	vtb->vtb_type = VTB_INVALID;
109}
110
111size_t
112sc_vtb_size(int cols, int rows)
113{
114	return (size_t)(cols*rows*sizeof(u_int16_t));
115}
116
117int
118sc_vtb_getc(sc_vtb_t *vtb, int at)
119{
120	if (vtb->vtb_type == VTB_FRAMEBUFFER)
121		return (readw(sc_vtb_pointer(vtb, at)) & 0x00ff);
122	else
123		return (*(u_int16_t *)sc_vtb_pointer(vtb, at) & 0x00ff);
124}
125
126int
127sc_vtb_geta(sc_vtb_t *vtb, int at)
128{
129	if (vtb->vtb_type == VTB_FRAMEBUFFER)
130		return (readw(sc_vtb_pointer(vtb, at)) & 0xff00);
131	else
132		return (*(u_int16_t *)sc_vtb_pointer(vtb, at) & 0xff00);
133}
134
135void
136sc_vtb_putc(sc_vtb_t *vtb, int at, int c, int a)
137{
138	if (vtb->vtb_type == VTB_FRAMEBUFFER)
139		writew(sc_vtb_pointer(vtb, at), a | c);
140	else
141		*(u_int16_t *)sc_vtb_pointer(vtb, at) = a | c;
142}
143
144vm_offset_t
145sc_vtb_putchar(sc_vtb_t *vtb, vm_offset_t p, int c, int a)
146{
147	if (vtb->vtb_type == VTB_FRAMEBUFFER)
148		writew(p, a | c);
149	else
150		*(u_int16_t *)p = a | c;
151	return (p + sizeof(u_int16_t));
152}
153
154vm_offset_t
155sc_vtb_pointer(sc_vtb_t *vtb, int at)
156{
157	return (vtb->vtb_buffer + sizeof(u_int16_t)*(at));
158}
159
160int
161sc_vtb_pos(sc_vtb_t *vtb, int pos, int offset)
162{
163	return ((pos + offset + vtb->vtb_size)%vtb->vtb_size);
164}
165
166void
167sc_vtb_clear(sc_vtb_t *vtb, int c, int attr)
168{
169	if (vtb->vtb_type == VTB_FRAMEBUFFER)
170		fillw_io(attr | c, sc_vtb_pointer(vtb, 0), vtb->vtb_size);
171	else
172		fillw(attr | c, (void *)sc_vtb_pointer(vtb, 0), vtb->vtb_size);
173}
174
175void
176sc_vtb_copy(sc_vtb_t *vtb1, int from, sc_vtb_t *vtb2, int to, int count)
177{
178	/* XXX if both are VTB_VRAMEBUFFER... */
179	if (vtb2->vtb_type == VTB_FRAMEBUFFER)
180		bcopy_toio(sc_vtb_pointer(vtb1, from),
181			   sc_vtb_pointer(vtb2, to),
182			   count*sizeof(u_int16_t));
183	else if (vtb1->vtb_type == VTB_FRAMEBUFFER)
184		bcopy_fromio(sc_vtb_pointer(vtb1, from),
185			     sc_vtb_pointer(vtb2, to),
186			     count*sizeof(u_int16_t));
187	else
188		bcopy((void *)sc_vtb_pointer(vtb1, from),
189		      (void *)sc_vtb_pointer(vtb2, to),
190		      count*sizeof(u_int16_t));
191}
192
193void
194sc_vtb_append(sc_vtb_t *vtb1, int from, sc_vtb_t *vtb2, int count)
195{
196	int len;
197
198	if (vtb2->vtb_type != VTB_RINGBUFFER)
199		return;
200
201	while (count > 0) {
202		len = imin(count, vtb2->vtb_size - vtb2->vtb_tail);
203		if (vtb1->vtb_type == VTB_FRAMEBUFFER)
204			bcopy_fromio(sc_vtb_pointer(vtb1, from),
205				     sc_vtb_pointer(vtb2, vtb2->vtb_tail),
206				     len*sizeof(u_int16_t));
207		else
208			bcopy((void *)sc_vtb_pointer(vtb1, from),
209			      (void *)sc_vtb_pointer(vtb2, vtb2->vtb_tail),
210			      len*sizeof(u_int16_t));
211		from += len;
212		count -= len;
213		vtb2->vtb_tail = vtb_wrap(vtb2, vtb2->vtb_tail, len);
214	}
215}
216
217void
218sc_vtb_seek(sc_vtb_t *vtb, int pos)
219{
220	vtb->vtb_tail = pos%vtb->vtb_size;
221}
222
223void
224sc_vtb_erase(sc_vtb_t *vtb, int at, int count, int c, int attr)
225{
226	if (at + count > vtb->vtb_size)
227		count = vtb->vtb_size - at;
228	if (vtb->vtb_type == VTB_FRAMEBUFFER)
229		fillw_io(attr | c, sc_vtb_pointer(vtb, at), count);
230	else
231		fillw(attr | c, (void *)sc_vtb_pointer(vtb, at), count);
232}
233
234void
235sc_vtb_move(sc_vtb_t *vtb, int from, int to, int count)
236{
237	if (from + count > vtb->vtb_size)
238		count = vtb->vtb_size - from;
239	if (to + count > vtb->vtb_size)
240		count = vtb->vtb_size - to;
241	if (count <= 0)
242		return;
243	if (vtb->vtb_type == VTB_FRAMEBUFFER)
244		bcopy_io(sc_vtb_pointer(vtb, from),
245			 sc_vtb_pointer(vtb, to), count*sizeof(u_int16_t));
246	else
247		bcopy((void *)sc_vtb_pointer(vtb, from),
248		      (void *)sc_vtb_pointer(vtb, to), count*sizeof(u_int16_t));
249}
250
251void
252sc_vtb_delete(sc_vtb_t *vtb, int at, int count, int c, int attr)
253{
254	int len;
255
256	if (at + count > vtb->vtb_size)
257		count = vtb->vtb_size - at;
258	len = vtb->vtb_size - at - count;
259	if (len > 0) {
260		if (vtb->vtb_type == VTB_FRAMEBUFFER)
261			bcopy_io(sc_vtb_pointer(vtb, at + count),
262				 sc_vtb_pointer(vtb, at),
263				 len*sizeof(u_int16_t));
264		else
265			bcopy((void *)sc_vtb_pointer(vtb, at + count),
266			      (void *)sc_vtb_pointer(vtb, at),
267			      len*sizeof(u_int16_t));
268	}
269	if (vtb->vtb_type == VTB_FRAMEBUFFER)
270		fillw_io(attr | c, sc_vtb_pointer(vtb, at + len),
271			 vtb->vtb_size - at - len);
272	else
273		fillw(attr | c, (void *)sc_vtb_pointer(vtb, at + len),
274		      vtb->vtb_size - at - len);
275}
276
277void
278sc_vtb_ins(sc_vtb_t *vtb, int at, int count, int c, int attr)
279{
280	if (at + count > vtb->vtb_size)
281		count = vtb->vtb_size - at;
282	else {
283		if (vtb->vtb_type == VTB_FRAMEBUFFER)
284			bcopy_io(sc_vtb_pointer(vtb, at),
285				 sc_vtb_pointer(vtb, at + count),
286				 (vtb->vtb_size - at - count)*sizeof(u_int16_t));
287		else
288			bcopy((void *)sc_vtb_pointer(vtb, at),
289			      (void *)sc_vtb_pointer(vtb, at + count),
290			      (vtb->vtb_size - at - count)*sizeof(u_int16_t));
291	}
292	if (vtb->vtb_type == VTB_FRAMEBUFFER)
293		fillw_io(attr | c, sc_vtb_pointer(vtb, at), count);
294	else
295		fillw(attr | c, (void *)sc_vtb_pointer(vtb, at), count);
296}
297