vt_fb.c revision 256904
1193323Sed/*-
2193323Sed * Copyright (c) 2013 The FreeBSD Foundation
3193323Sed * All rights reserved.
4193323Sed *
5193323Sed * This software was developed by Aleksandr Rybalko under sponsorship from the
6193323Sed * FreeBSD Foundation.
7193323Sed *
8193323Sed * Redistribution and use in source and binary forms, with or without
9193323Sed * modification, are permitted provided that the following conditions
10193323Sed * are met:
11193323Sed * 1. Redistributions of source code must retain the above copyright
12193323Sed *    notice, this list of conditions and the following disclaimer.
13193323Sed * 2. Redistributions in binary form must reproduce the above copyright
14193323Sed *    notice, this list of conditions and the following disclaimer in the
15193323Sed *    documentation and/or other materials provided with the distribution.
16193323Sed *
17249423Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18249423Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20249423Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22243830Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27193323Sed * SUCH DAMAGE.
28193323Sed *
29193323Sed * $FreeBSD: user/ed/newcons/sys/dev/vt/hw/fb/vt_fb.c 256904 2013-10-22 14:39:32Z ray $
30193323Sed */
31193323Sed
32193323Sed#include <sys/cdefs.h>
33193323Sed__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/vt/hw/fb/vt_fb.c 256904 2013-10-22 14:39:32Z ray $");
34193323Sed
35193323Sed#include <sys/param.h>
36193323Sed#include <sys/systm.h>
37193323Sed#include <sys/malloc.h>
38193323Sed#include <sys/queue.h>
39193323Sed#include <sys/fbio.h>
40193323Sed#include <dev/vt/vt.h>
41193323Sed#include <dev/vt/hw/fb/vt_fb.h>
42193323Sed#include <dev/vt/colors/vt_termcolors.h>
43249423Sdim
44249423Sdimstatic vd_init_t	vt_fb_init;
45249423Sdimstatic vd_blank_t	vt_fb_blank;
46193323Sedstatic vd_bitbltchr_t	vt_fb_bitbltchr;
47249423Sdimstatic vd_postswitch_t	vt_fb_postswitch;
48249423Sdim
49193323Sedstatic struct vt_driver vt_fb_driver = {
50249423Sdim	.vd_init = vt_fb_init,
51249423Sdim	.vd_blank = vt_fb_blank,
52249423Sdim	.vd_bitbltchr = vt_fb_bitbltchr,
53193323Sed	.vd_postswitch = vt_fb_postswitch,
54249423Sdim	.vd_priority = VD_PRIORITY_GENERIC+10,
55249423Sdim};
56249423Sdim
57193323Sedstatic void
58249423Sdimvt_fb_blank(struct vt_device *vd, term_color_t color)
59249423Sdim{
60249423Sdim	struct fb_info *info;
61193323Sed	uint32_t c;
62193323Sed	u_int o;
63193323Sed
64193323Sed	info = vd->vd_softc;
65193323Sed	c = info->fb_cmap[color];
66193323Sed	switch (FBTYPE_GET_BYTESPP(info)) {
67193323Sed	case 1:
68193323Sed		for (o = 0; o < info->fb_stride; o++)
69193323Sed			info->wr1(info, o, c);
70234353Sdim		break;
71234353Sdim	case 2:
72234353Sdim		for (o = 0; o < info->fb_stride; o += 2)
73234353Sdim			info->wr2(info, o, c);
74193323Sed		break;
75193323Sed	case 3:
76249423Sdim		/* line 0 */
77193323Sed		for (o = 0; o < info->fb_stride; o += 3) {
78193323Sed			info->wr1(info, o, (c >> 16) & 0xff);
79193323Sed			info->wr1(info, o + 1, (c >> 8) & 0xff);
80193323Sed			info->wr1(info, o + 2, c & 0xff);
81193323Sed		}
82198090Srdivacky		break;
83198090Srdivacky	case 4:
84198090Srdivacky		for (o = 0; o < info->fb_stride; o += 4)
85198090Srdivacky			info->wr4(info, o, c);
86198090Srdivacky		break;
87193323Sed	default:
88193323Sed		/* panic? */
89198090Srdivacky		return;
90198090Srdivacky	}
91193323Sed	/* Copy line0 to all other lines. */
92193323Sed	/* XXX will copy with borders. */
93193323Sed	for (o = 1; o < info->fb_height; o++) {
94193323Sed		memmove((void *)(info->fb_vbase + o * info->fb_stride),
95193323Sed		    (void *)info->fb_vbase, info->fb_stride);
96249423Sdim	}
97249423Sdim}
98249423Sdim
99249423Sdimstatic void
100249423Sdimvt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src,
101249423Sdim    vt_axis_t top, vt_axis_t left, unsigned int width, unsigned int height,
102249423Sdim    term_color_t fg, term_color_t bg)
103249423Sdim{
104249423Sdim	struct fb_info *info;
105193323Sed	uint32_t fgc, bgc, cc, o;
106249423Sdim	int c, l, bpp;
107249423Sdim	u_long line;
108249423Sdim	uint8_t b;
109249423Sdim
110249423Sdim	b = 0;
111193323Sed	info = vd->vd_softc;
112249423Sdim	bpp = FBTYPE_GET_BYTESPP(info);
113249423Sdim	fgc = info->fb_cmap[fg];
114249423Sdim	bgc = info->fb_cmap[bg];
115249423Sdim
116193323Sed	line = (info->fb_stride * top) + (left * bpp);
117193323Sed	for (l = 0; l < height; l++) {
118193323Sed		for (c = 0; c < width; c++) {
119210299Sed			if (c % 8 == 0)
120210299Sed				b = *src++;
121221345Sdim			else
122210299Sed				b <<= 1;
123193323Sed			o = line + (c * bpp);
124198090Srdivacky			cc = b & 0x80 ? fgc : bgc;
125198090Srdivacky
126193323Sed			switch(bpp) {
127249423Sdim			case 1:
128249423Sdim				info->wr1(info, o, cc);
129249423Sdim				break;
130249423Sdim			case 2:
131193323Sed				info->wr2(info, o, cc);
132249423Sdim				break;
133249423Sdim			case 3:
134263508Sdim				/* Packed mode, so unaligned. Byte access. */
135249423Sdim				info->wr1(info, o, (cc >> 16) & 0xff);
136249423Sdim				info->wr1(info, o + 1, (cc >> 8) & 0xff);
137249423Sdim				info->wr1(info, o + 2, cc & 0xff);
138249423Sdim				break;
139249423Sdim			case 4:
140249423Sdim				info->wr4(info, o, cc);
141249423Sdim				break;
142249423Sdim			default:
143249423Sdim				/* panic? */
144263508Sdim				break;
145249423Sdim			}
146249423Sdim		}
147249423Sdim		line += info->fb_stride;
148249423Sdim	}
149249423Sdim}
150193323Sed
151193323Sedstatic void
152193323Sedvt_fb_postswitch(struct vt_device *vd)
153193323Sed{
154193323Sed	struct fb_info *info;
155193323Sed
156193323Sed	info = vd->vd_softc;
157193323Sed
158193323Sed	if (info->enter != NULL)
159193323Sed		info->enter(info->fb_priv);
160198090Srdivacky}
161198090Srdivacky
162198090Srdivackystatic int
163193323Sedvt_fb_init_cmap(uint32_t *cmap, int depth)
164198090Srdivacky{
165243830Sdim
166193323Sed	switch (depth) {
167249423Sdim	case 8:
168249423Sdim		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
169249423Sdim		    0x7, 5, 0x7, 2, 0x3, 0));
170198090Srdivacky	case 15:
171249423Sdim		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
172249423Sdim		    0x1f, 10, 0x1f, 5, 0x1f, 0));
173234353Sdim	case 16:
174198090Srdivacky		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
175198090Srdivacky		    0x1f, 11, 0x3f, 5, 0x1f, 0));
176198090Srdivacky	case 24:
177198090Srdivacky	case 32: /* Ignore alpha. */
178198090Srdivacky		return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB,
179198090Srdivacky		    0xff, 0, 0xff, 8, 0xff, 16));
180198090Srdivacky	default:
181234353Sdim		return (1);
182198090Srdivacky	}
183198090Srdivacky}
184198090Srdivacky
185198090Srdivackystatic int
186198090Srdivackyvt_fb_init(struct vt_device *vd)
187249423Sdim{
188249423Sdim	struct fb_info *info;
189249423Sdim	int err;
190249423Sdim
191198090Srdivacky	info = vd->vd_softc;
192198090Srdivacky	vd->vd_height = info->fb_height;
193198090Srdivacky	vd->vd_width = info->fb_width;
194210299Sed
195210299Sed	if (info->fb_cmsize <= 0) {
196210299Sed		err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info));
197210299Sed		if (err)
198210299Sed			return (CN_DEAD);
199210299Sed		info->fb_cmsize = 16;
200198090Srdivacky	}
201198090Srdivacky
202198090Srdivacky	/* Clear the screen. */
203198090Srdivacky	vt_fb_blank(vd, TC_BLACK);
204193323Sed
205198090Srdivacky	/* Wakeup screen. KMS need this. */
206193323Sed	vt_fb_postswitch(vd);
207193323Sed
208193323Sed	return (CN_INTERNAL);
209}
210
211int
212vt_fb_attach(struct fb_info *info)
213{
214
215	vt_allocate(&vt_fb_driver, info);
216	return (0);
217}
218