vt_fb.c revision 258781
1/*-
2 * Copyright (c) 2013 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Aleksandr Rybalko under sponsorship from the
6 * FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: user/ed/newcons/sys/dev/vt/hw/fb/vt_fb.c 258781 2013-11-30 22:46:43Z nwhitehorn $
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/vt/hw/fb/vt_fb.c 258781 2013-11-30 22:46:43Z nwhitehorn $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/malloc.h>
38#include <sys/queue.h>
39#include <sys/fbio.h>
40#include <dev/vt/vt.h>
41#include <dev/vt/hw/fb/vt_fb.h>
42#include <dev/vt/colors/vt_termcolors.h>
43
44static struct vt_driver vt_fb_driver = {
45	.vd_init = vt_fb_init,
46	.vd_blank = vt_fb_blank,
47	.vd_bitbltchr = vt_fb_bitbltchr,
48	.vd_postswitch = vt_fb_postswitch,
49	.vd_priority = VD_PRIORITY_GENERIC+10,
50};
51
52void
53vt_fb_blank(struct vt_device *vd, term_color_t color)
54{
55	struct fb_info *info;
56	uint32_t c;
57	u_int o;
58
59	info = vd->vd_softc;
60	c = info->fb_cmap[color];
61
62	switch (FBTYPE_GET_BYTESPP(info)) {
63	case 1:
64		for (o = 0; o < info->fb_stride; o++)
65			info->wr1(info, o, c);
66		break;
67	case 2:
68		for (o = 0; o < info->fb_stride; o += 2)
69			info->wr2(info, o, c);
70		break;
71	case 3:
72		/* line 0 */
73		for (o = 0; o < info->fb_stride; o += 3) {
74			info->wr1(info, o, (c >> 16) & 0xff);
75			info->wr1(info, o + 1, (c >> 8) & 0xff);
76			info->wr1(info, o + 2, c & 0xff);
77		}
78		break;
79	case 4:
80		for (o = 0; o < info->fb_stride; o += 4)
81			info->wr4(info, o, c);
82		break;
83	default:
84		/* panic? */
85		return;
86	}
87	/* Copy line0 to all other lines. */
88	/* XXX will copy with borders. */
89	for (o = info->fb_stride; o < info->fb_size; o += info->fb_stride) {
90		info->copy(info, o, 0, info->fb_stride);
91	}
92}
93
94void
95vt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
96    int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
97    unsigned int height, term_color_t fg, term_color_t bg)
98{
99	struct fb_info *info;
100	uint32_t fgc, bgc, cc, o;
101	int c, l, bpp;
102	u_long line;
103	uint8_t b, m;
104	const uint8_t *ch;
105
106	info = vd->vd_softc;
107	bpp = FBTYPE_GET_BYTESPP(info);
108	fgc = info->fb_cmap[fg];
109	bgc = info->fb_cmap[bg];
110	b = m = 0;
111	if (bpl == 0)
112		bpl = (width + 7) >> 3; /* Bytes per sorce line. */
113
114	/* Don't try to put off screen pixels */
115	if (((left + width) > info->fb_width) || ((top + height) >
116	    info->fb_height))
117		return;
118
119	line = (info->fb_stride * top) + (left * bpp);
120	for (l = 0; l < height; l++) {
121		ch = src;
122		for (c = 0; c < width; c++) {
123			if (c % 8 == 0)
124				b = *ch++;
125			else
126				b <<= 1;
127			if (mask != NULL) {
128				if (c % 8 == 0)
129					m = *mask++;
130				else
131					m <<= 1;
132				/* Skip pixel write, if mask has no bit set. */
133				if ((m & 0x80) == 0)
134					continue;
135			}
136			o = line + (c * bpp);
137			cc = b & 0x80 ? fgc : bgc;
138
139			switch(bpp) {
140			case 1:
141				info->wr1(info, o, cc);
142				break;
143			case 2:
144				info->wr2(info, o, cc);
145				break;
146			case 3:
147				/* Packed mode, so unaligned. Byte access. */
148				info->wr1(info, o, (cc >> 16) & 0xff);
149				info->wr1(info, o + 1, (cc >> 8) & 0xff);
150				info->wr1(info, o + 2, cc & 0xff);
151				break;
152			case 4:
153				info->wr4(info, o, cc);
154				break;
155			default:
156				/* panic? */
157				break;
158			}
159		}
160		line += info->fb_stride;
161		src += bpl;
162	}
163}
164
165void
166vt_fb_postswitch(struct vt_device *vd)
167{
168	struct fb_info *info;
169
170	info = vd->vd_softc;
171
172	if (info->enter != NULL)
173		info->enter(info->fb_priv);
174}
175
176static int
177vt_fb_init_cmap(uint32_t *cmap, int depth)
178{
179
180	switch (depth) {
181	case 8:
182		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
183		    0x7, 5, 0x7, 2, 0x3, 0));
184	case 15:
185		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
186		    0x1f, 10, 0x1f, 5, 0x1f, 0));
187	case 16:
188		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
189		    0x1f, 11, 0x3f, 5, 0x1f, 0));
190	case 24:
191	case 32: /* Ignore alpha. */
192		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
193		    0xff, 0, 0xff, 8, 0xff, 16));
194	default:
195		return (1);
196	}
197}
198
199int
200vt_fb_init(struct vt_device *vd)
201{
202	struct fb_info *info;
203	int err;
204
205	info = vd->vd_softc;
206	vd->vd_height = info->fb_height;
207	vd->vd_width = info->fb_width;
208
209	if (info->fb_cmsize <= 0) {
210		err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info));
211		if (err)
212			return (CN_DEAD);
213		info->fb_cmsize = 16;
214	}
215
216	/* Clear the screen. */
217	vt_fb_blank(vd, TC_BLACK);
218
219	/* Wakeup screen. KMS need this. */
220	vt_fb_postswitch(vd);
221
222	return (CN_INTERNAL);
223}
224
225int
226vt_fb_attach(struct fb_info *info)
227{
228
229	vt_allocate(&vt_fb_driver, info);
230
231	return (0);
232}
233
234void
235vt_fb_resume(void)
236{
237
238	vt_resume();
239}
240
241void
242vt_fb_suspend(void)
243{
244
245	vt_suspend();
246}
247