xref: /freebsd-src/sys/dev/vt/hw/fb/vt_fb.c (revision 0782240958117692ab9861abb5483c9e64f6bc39)
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$
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
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 
44 static 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 
52 void
53 vt_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 
94 void
95 vt_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 
165 void
166 vt_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 
176 static int
177 vt_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 
199 int
200 vt_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 
225 int
226 vt_fb_attach(struct fb_info *info)
227 {
228 
229 	vt_allocate(&vt_fb_driver, info);
230 
231 	return (0);
232 }
233 
234 void
235 vt_fb_resume(void)
236 {
237 
238 	vt_resume();
239 }
240 
241 void
242 vt_fb_suspend(void)
243 {
244 
245 	vt_suspend();
246 }
247