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