vt_fb.c revision 257725
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 257725 2013-11-05 23:01:57Z ray $
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/vt/hw/fb/vt_fb.c 257725 2013-11-05 23:01:57Z ray $");
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,
96    vt_axis_t top, vt_axis_t left, unsigned int width, unsigned int height,
97    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;
104
105	b = 0;
106	info = vd->vd_softc;
107	bpp = FBTYPE_GET_BYTESPP(info);
108	fgc = info->fb_cmap[fg];
109	bgc = info->fb_cmap[bg];
110
111	line = (info->fb_stride * top) + (left * bpp);
112	for (l = 0; l < height; l++) {
113		for (c = 0; c < width; c++) {
114			if (c % 8 == 0)
115				b = *src++;
116			else
117				b <<= 1;
118			o = line + (c * bpp);
119			cc = b & 0x80 ? fgc : bgc;
120
121			switch(bpp) {
122			case 1:
123				info->wr1(info, o, cc);
124				break;
125			case 2:
126				info->wr2(info, o, cc);
127				break;
128			case 3:
129				/* Packed mode, so unaligned. Byte access. */
130				info->wr1(info, o, (cc >> 16) & 0xff);
131				info->wr1(info, o + 1, (cc >> 8) & 0xff);
132				info->wr1(info, o + 2, cc & 0xff);
133				break;
134			case 4:
135				info->wr4(info, o, cc);
136				break;
137			default:
138				/* panic? */
139				break;
140			}
141		}
142		line += info->fb_stride;
143	}
144}
145
146void
147vt_fb_postswitch(struct vt_device *vd)
148{
149	struct fb_info *info;
150
151	info = vd->vd_softc;
152
153	if (info->enter != NULL)
154		info->enter(info->fb_priv);
155}
156
157static int
158vt_fb_init_cmap(uint32_t *cmap, int depth)
159{
160
161	switch (depth) {
162	case 8:
163		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
164		    0x7, 5, 0x7, 2, 0x3, 0));
165	case 15:
166		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
167		    0x1f, 10, 0x1f, 5, 0x1f, 0));
168	case 16:
169		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
170		    0x1f, 11, 0x3f, 5, 0x1f, 0));
171	case 24:
172	case 32: /* Ignore alpha. */
173		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
174		    0xff, 0, 0xff, 8, 0xff, 16));
175	default:
176		return (1);
177	}
178}
179
180int
181vt_fb_init(struct vt_device *vd)
182{
183	struct fb_info *info;
184	int err;
185
186	info = vd->vd_softc;
187	vd->vd_height = info->fb_height;
188	vd->vd_width = info->fb_width;
189
190	if (info->fb_cmsize <= 0) {
191		err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info));
192		if (err)
193			return (CN_DEAD);
194		info->fb_cmsize = 16;
195	}
196
197	/* Clear the screen. */
198	vt_fb_blank(vd, TC_BLACK);
199
200	/* Wakeup screen. KMS need this. */
201	vt_fb_postswitch(vd);
202
203	return (CN_INTERNAL);
204}
205
206int
207vt_fb_attach(struct fb_info *info)
208{
209
210	vt_allocate(&vt_fb_driver, info);
211
212	return (0);
213}
214