vt_fb.c revision 257988
1166255Sdelphij/*-
2166255Sdelphij * Copyright (c) 2013 The FreeBSD Foundation
3166255Sdelphij * All rights reserved.
4166255Sdelphij *
5166255Sdelphij * This software was developed by Aleksandr Rybalko under sponsorship from the
6166255Sdelphij * FreeBSD Foundation.
7166255Sdelphij *
8166255Sdelphij * Redistribution and use in source and binary forms, with or without
9166255Sdelphij * modification, are permitted provided that the following conditions
10166255Sdelphij * are met:
11166255Sdelphij * 1. Redistributions of source code must retain the above copyright
12166255Sdelphij *    notice, this list of conditions and the following disclaimer.
13166255Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
14166255Sdelphij *    notice, this list of conditions and the following disclaimer in the
15166255Sdelphij *    documentation and/or other materials provided with the distribution.
16166255Sdelphij *
17166255Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18166255Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19166255Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20166255Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21166255Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22166255Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23166255Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24166255Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25166255Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26166255Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27166255Sdelphij * SUCH DAMAGE.
28166255Sdelphij *
29166255Sdelphij * $FreeBSD: user/ed/newcons/sys/dev/vt/hw/fb/vt_fb.c 257988 2013-11-11 13:25:49Z ray $
30166255Sdelphij */
31166255Sdelphij
32166255Sdelphij#include <sys/cdefs.h>
33166255Sdelphij__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/vt/hw/fb/vt_fb.c 257988 2013-11-11 13:25:49Z ray $");
34166255Sdelphij
35166255Sdelphij#include <sys/param.h>
36166255Sdelphij#include <sys/systm.h>
37166255Sdelphij#include <sys/malloc.h>
38166255Sdelphij#include <sys/queue.h>
39166255Sdelphij#include <sys/fbio.h>
40166255Sdelphij#include <dev/vt/vt.h>
41166255Sdelphij#include <dev/vt/hw/fb/vt_fb.h>
42166255Sdelphij#include <dev/vt/colors/vt_termcolors.h>
43166255Sdelphij
44166255Sdelphijstatic struct vt_driver vt_fb_driver = {
45166255Sdelphij	.vd_init = vt_fb_init,
46166255Sdelphij	.vd_blank = vt_fb_blank,
47166255Sdelphij	.vd_bitbltchr = vt_fb_bitbltchr,
48166255Sdelphij	.vd_postswitch = vt_fb_postswitch,
49166255Sdelphij	.vd_priority = VD_PRIORITY_GENERIC+10,
50166255Sdelphij};
51166255Sdelphij
52166255Sdelphijvoid
53166255Sdelphijvt_fb_blank(struct vt_device *vd, term_color_t color)
54166255Sdelphij{
55166255Sdelphij	struct fb_info *info;
56166255Sdelphij	uint32_t c;
57166255Sdelphij	u_int o;
58166255Sdelphij
59166255Sdelphij	info = vd->vd_softc;
60166255Sdelphij	c = info->fb_cmap[color];
61166255Sdelphij
62166255Sdelphij	switch (FBTYPE_GET_BYTESPP(info)) {
63166255Sdelphij	case 1:
64166255Sdelphij		for (o = 0; o < info->fb_stride; o++)
65166255Sdelphij			info->wr1(info, o, c);
66166255Sdelphij		break;
67166255Sdelphij	case 2:
68166255Sdelphij		for (o = 0; o < info->fb_stride; o += 2)
69166255Sdelphij			info->wr2(info, o, c);
70166255Sdelphij		break;
71166255Sdelphij	case 3:
72166255Sdelphij		/* line 0 */
73166255Sdelphij		for (o = 0; o < info->fb_stride; o += 3) {
74166255Sdelphij			info->wr1(info, o, (c >> 16) & 0xff);
75166255Sdelphij			info->wr1(info, o + 1, (c >> 8) & 0xff);
76166255Sdelphij			info->wr1(info, o + 2, c & 0xff);
77166255Sdelphij		}
78166255Sdelphij		break;
79166255Sdelphij	case 4:
80166255Sdelphij		for (o = 0; o < info->fb_stride; o += 4)
81166255Sdelphij			info->wr4(info, o, c);
82166255Sdelphij		break;
83166255Sdelphij	default:
84166255Sdelphij		/* panic? */
85166255Sdelphij		return;
86166255Sdelphij	}
87166255Sdelphij	/* Copy line0 to all other lines. */
88166255Sdelphij	/* XXX will copy with borders. */
89166255Sdelphij	for (o = info->fb_stride; o < info->fb_size; o += info->fb_stride) {
90166255Sdelphij		info->copy(info, o, 0, info->fb_stride);
91166255Sdelphij	}
92166255Sdelphij}
93166255Sdelphij
94166255Sdelphijvoid
95166255Sdelphijvt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
96166255Sdelphij    int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
97166255Sdelphij    unsigned int height, term_color_t fg, term_color_t bg)
98166255Sdelphij{
99166255Sdelphij	struct fb_info *info;
100166255Sdelphij	uint32_t fgc, bgc, cc, o;
101166255Sdelphij	int c, l, bpp;
102166255Sdelphij	u_long line;
103166255Sdelphij	uint8_t b, m;
104166255Sdelphij	const uint8_t *ch;
105166255Sdelphij
106166255Sdelphij	info = vd->vd_softc;
107166255Sdelphij	bpp = FBTYPE_GET_BYTESPP(info);
108166255Sdelphij	fgc = info->fb_cmap[fg];
109166255Sdelphij	bgc = info->fb_cmap[bg];
110166255Sdelphij	if (bpl == 0)
111166255Sdelphij		bpl = (width + 7) >> 3; /* Bytes per sorce line. */
112166255Sdelphij
113166255Sdelphij	/* Don't try to put off screen pixels */
114166255Sdelphij	if (((left + width) > info->fb_width) || ((top + height) >
115166255Sdelphij	    info->fb_height))
116166255Sdelphij		return;
117166255Sdelphij
118166255Sdelphij	line = (info->fb_stride * top) + (left * bpp);
119166255Sdelphij	for (l = 0; l < height; l++) {
120166255Sdelphij		ch = src;
121166255Sdelphij		for (c = 0; c < width; c++) {
122166255Sdelphij			if (c % 8 == 0)
123166255Sdelphij				b = *ch++;
124166255Sdelphij			else
125166255Sdelphij				b <<= 1;
126166255Sdelphij			if (mask != NULL) {
127166255Sdelphij				if (c % 8 == 0)
128166255Sdelphij					m = *mask++;
129				else
130					m <<= 1;
131				/* Skip pixel write, if mask has no bit set. */
132				if ((m & 0x80) == 0)
133					continue;
134			}
135			o = line + (c * bpp);
136			cc = b & 0x80 ? fgc : bgc;
137
138			switch(bpp) {
139			case 1:
140				info->wr1(info, o, cc);
141				break;
142			case 2:
143				info->wr2(info, o, cc);
144				break;
145			case 3:
146				/* Packed mode, so unaligned. Byte access. */
147				info->wr1(info, o, (cc >> 16) & 0xff);
148				info->wr1(info, o + 1, (cc >> 8) & 0xff);
149				info->wr1(info, o + 2, cc & 0xff);
150				break;
151			case 4:
152				info->wr4(info, o, cc);
153				break;
154			default:
155				/* panic? */
156				break;
157			}
158		}
159		line += info->fb_stride;
160		src += bpl;
161	}
162}
163
164void
165vt_fb_postswitch(struct vt_device *vd)
166{
167	struct fb_info *info;
168
169	info = vd->vd_softc;
170
171	if (info->enter != NULL)
172		info->enter(info->fb_priv);
173}
174
175static int
176vt_fb_init_cmap(uint32_t *cmap, int depth)
177{
178
179	switch (depth) {
180	case 8:
181		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
182		    0x7, 5, 0x7, 2, 0x3, 0));
183	case 15:
184		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
185		    0x1f, 10, 0x1f, 5, 0x1f, 0));
186	case 16:
187		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
188		    0x1f, 11, 0x3f, 5, 0x1f, 0));
189	case 24:
190	case 32: /* Ignore alpha. */
191		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
192		    0xff, 0, 0xff, 8, 0xff, 16));
193	default:
194		return (1);
195	}
196}
197
198int
199vt_fb_init(struct vt_device *vd)
200{
201	struct fb_info *info;
202	int err;
203
204	info = vd->vd_softc;
205	vd->vd_height = info->fb_height;
206	vd->vd_width = info->fb_width;
207
208	if (info->fb_cmsize <= 0) {
209		err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info));
210		if (err)
211			return (CN_DEAD);
212		info->fb_cmsize = 16;
213	}
214
215	/* Clear the screen. */
216	vt_fb_blank(vd, TC_BLACK);
217
218	/* Wakeup screen. KMS need this. */
219	vt_fb_postswitch(vd);
220
221	return (CN_INTERNAL);
222}
223
224int
225vt_fb_attach(struct fb_info *info)
226{
227
228	vt_allocate(&vt_fb_driver, info);
229
230	return (0);
231}
232
233void
234vt_fb_resume(void)
235{
236
237	vt_resume();
238}
239
240void
241vt_fb_suspend(void)
242{
243
244	vt_suspend();
245}
246