xref: /freebsd/sys/dev/vt/hw/fb/vt_fb.c (revision 2c48063b30e78e982be84d2d1df4a3b96e3f3325)
127cf7d04SAleksandr Rybalko /*-
227cf7d04SAleksandr Rybalko  * Copyright (c) 2013 The FreeBSD Foundation
327cf7d04SAleksandr Rybalko  * All rights reserved.
427cf7d04SAleksandr Rybalko  *
527cf7d04SAleksandr Rybalko  * This software was developed by Aleksandr Rybalko under sponsorship from the
627cf7d04SAleksandr Rybalko  * FreeBSD Foundation.
727cf7d04SAleksandr Rybalko  *
827cf7d04SAleksandr Rybalko  * Redistribution and use in source and binary forms, with or without
927cf7d04SAleksandr Rybalko  * modification, are permitted provided that the following conditions
1027cf7d04SAleksandr Rybalko  * are met:
1127cf7d04SAleksandr Rybalko  * 1. Redistributions of source code must retain the above copyright
1227cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer.
1327cf7d04SAleksandr Rybalko  * 2. Redistributions in binary form must reproduce the above copyright
1427cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer in the
1527cf7d04SAleksandr Rybalko  *    documentation and/or other materials provided with the distribution.
1627cf7d04SAleksandr Rybalko  *
1727cf7d04SAleksandr Rybalko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1827cf7d04SAleksandr Rybalko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1927cf7d04SAleksandr Rybalko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2027cf7d04SAleksandr Rybalko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2127cf7d04SAleksandr Rybalko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2227cf7d04SAleksandr Rybalko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2327cf7d04SAleksandr Rybalko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2427cf7d04SAleksandr Rybalko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2527cf7d04SAleksandr Rybalko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2627cf7d04SAleksandr Rybalko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2727cf7d04SAleksandr Rybalko  * SUCH DAMAGE.
2827cf7d04SAleksandr Rybalko  *
2927cf7d04SAleksandr Rybalko  * $FreeBSD$
3027cf7d04SAleksandr Rybalko  */
3127cf7d04SAleksandr Rybalko 
3227cf7d04SAleksandr Rybalko #include <sys/cdefs.h>
3327cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$");
3427cf7d04SAleksandr Rybalko 
3527cf7d04SAleksandr Rybalko #include <sys/param.h>
3627cf7d04SAleksandr Rybalko #include <sys/systm.h>
3727cf7d04SAleksandr Rybalko #include <sys/malloc.h>
3827cf7d04SAleksandr Rybalko #include <sys/queue.h>
3927cf7d04SAleksandr Rybalko #include <sys/fbio.h>
4027cf7d04SAleksandr Rybalko #include <dev/vt/vt.h>
4127cf7d04SAleksandr Rybalko #include <dev/vt/hw/fb/vt_fb.h>
4227cf7d04SAleksandr Rybalko #include <dev/vt/colors/vt_termcolors.h>
4327cf7d04SAleksandr Rybalko 
44a985ae9bSHans Petter Selasky #include <vm/vm.h>
45a985ae9bSHans Petter Selasky #include <vm/pmap.h>
46a985ae9bSHans Petter Selasky 
4727cf7d04SAleksandr Rybalko static struct vt_driver vt_fb_driver = {
484dde1640SAleksandr Rybalko 	.vd_name = "fb",
4927cf7d04SAleksandr Rybalko 	.vd_init = vt_fb_init,
5076e2f976SJean-Sébastien Pédron 	.vd_fini = vt_fb_fini,
5127cf7d04SAleksandr Rybalko 	.vd_blank = vt_fb_blank,
52c285e4a5SJean-Sébastien Pédron 	.vd_bitblt_text = vt_fb_bitblt_text,
53631bb572SJean-Sébastien Pédron 	.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
549e497e7bSAleksandr Rybalko 	.vd_drawrect = vt_fb_drawrect,
559e497e7bSAleksandr Rybalko 	.vd_setpixel = vt_fb_setpixel,
5627cf7d04SAleksandr Rybalko 	.vd_postswitch = vt_fb_postswitch,
5727cf7d04SAleksandr Rybalko 	.vd_priority = VD_PRIORITY_GENERIC+10,
587a1a32c4SAleksandr Rybalko 	.vd_fb_ioctl = vt_fb_ioctl,
597a1a32c4SAleksandr Rybalko 	.vd_fb_mmap = vt_fb_mmap,
606dfa4578SAndriy Gapon 	.vd_suspend = vt_fb_suspend,
616dfa4578SAndriy Gapon 	.vd_resume = vt_fb_resume,
6227cf7d04SAleksandr Rybalko };
6327cf7d04SAleksandr Rybalko 
644dde1640SAleksandr Rybalko VT_DRIVER_DECLARE(vt_fb, vt_fb_driver);
654dde1640SAleksandr Rybalko 
669ed297c8SNathan Whitehorn static void
679ed297c8SNathan Whitehorn vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v)
689ed297c8SNathan Whitehorn {
699ed297c8SNathan Whitehorn 
709ed297c8SNathan Whitehorn 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
719ed297c8SNathan Whitehorn 	*(uint8_t *)(sc->fb_vbase + o) = v;
729ed297c8SNathan Whitehorn }
739ed297c8SNathan Whitehorn 
749ed297c8SNathan Whitehorn static void
759ed297c8SNathan Whitehorn vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v)
769ed297c8SNathan Whitehorn {
779ed297c8SNathan Whitehorn 
789ed297c8SNathan Whitehorn 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
799ed297c8SNathan Whitehorn 	*(uint16_t *)(sc->fb_vbase + o) = v;
809ed297c8SNathan Whitehorn }
819ed297c8SNathan Whitehorn 
829ed297c8SNathan Whitehorn static void
839ed297c8SNathan Whitehorn vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v)
849ed297c8SNathan Whitehorn {
859ed297c8SNathan Whitehorn 
869ed297c8SNathan Whitehorn 	KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
879ed297c8SNathan Whitehorn 	*(uint32_t *)(sc->fb_vbase + o) = v;
889ed297c8SNathan Whitehorn }
899ed297c8SNathan Whitehorn 
9060d7ea3dSNathan Whitehorn int
917a1a32c4SAleksandr Rybalko vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td)
927a1a32c4SAleksandr Rybalko {
937a1a32c4SAleksandr Rybalko 	struct fb_info *info;
9460d7ea3dSNathan Whitehorn 	int error = 0;
957a1a32c4SAleksandr Rybalko 
967a1a32c4SAleksandr Rybalko 	info = vd->vd_softc;
977a1a32c4SAleksandr Rybalko 
9860d7ea3dSNathan Whitehorn 	switch (cmd) {
9960d7ea3dSNathan Whitehorn 	case FBIOGTYPE:
10060d7ea3dSNathan Whitehorn 		bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
10160d7ea3dSNathan Whitehorn 		break;
1027a1a32c4SAleksandr Rybalko 
10360d7ea3dSNathan Whitehorn 	case FBIO_GETWINORG:	/* get frame buffer window origin */
10460d7ea3dSNathan Whitehorn 		*(u_int *)data = 0;
10560d7ea3dSNathan Whitehorn 		break;
10660d7ea3dSNathan Whitehorn 
10760d7ea3dSNathan Whitehorn 	case FBIO_GETDISPSTART:	/* get display start address */
10860d7ea3dSNathan Whitehorn 		((video_display_start_t *)data)->x = 0;
10960d7ea3dSNathan Whitehorn 		((video_display_start_t *)data)->y = 0;
11060d7ea3dSNathan Whitehorn 		break;
11160d7ea3dSNathan Whitehorn 
11260d7ea3dSNathan Whitehorn 	case FBIO_GETLINEWIDTH:	/* get scan line width in bytes */
11360d7ea3dSNathan Whitehorn 		*(u_int *)data = info->fb_stride;
11460d7ea3dSNathan Whitehorn 		break;
11560d7ea3dSNathan Whitehorn 
11660d7ea3dSNathan Whitehorn 	case FBIO_BLANK:	/* blank display */
11760d7ea3dSNathan Whitehorn 		if (vd->vd_driver->vd_blank == NULL)
11860d7ea3dSNathan Whitehorn 			return (ENODEV);
11960d7ea3dSNathan Whitehorn 		vd->vd_driver->vd_blank(vd, TC_BLACK);
12060d7ea3dSNathan Whitehorn 		break;
12160d7ea3dSNathan Whitehorn 
12260d7ea3dSNathan Whitehorn 	default:
12360d7ea3dSNathan Whitehorn 		error = ENOIOCTL;
12460d7ea3dSNathan Whitehorn 		break;
1257a1a32c4SAleksandr Rybalko 	}
1267a1a32c4SAleksandr Rybalko 
12760d7ea3dSNathan Whitehorn 	return (error);
12860d7ea3dSNathan Whitehorn }
12960d7ea3dSNathan Whitehorn 
13060d7ea3dSNathan Whitehorn int
1315beb07abSAleksandr Rybalko vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr,
1325beb07abSAleksandr Rybalko     int prot, vm_memattr_t *memattr)
1337a1a32c4SAleksandr Rybalko {
1347a1a32c4SAleksandr Rybalko 	struct fb_info *info;
1357a1a32c4SAleksandr Rybalko 
1367a1a32c4SAleksandr Rybalko 	info = vd->vd_softc;
1377a1a32c4SAleksandr Rybalko 
13860d7ea3dSNathan Whitehorn 	if (info->fb_flags & FB_FLAG_NOMMAP)
13960d7ea3dSNathan Whitehorn 		return (ENODEV);
1407a1a32c4SAleksandr Rybalko 
14160d7ea3dSNathan Whitehorn 	if (offset >= 0 && offset < info->fb_size) {
142a985ae9bSHans Petter Selasky 		if (info->fb_pbase == 0) {
143a985ae9bSHans Petter Selasky 			*paddr = vtophys((uint8_t *)info->fb_vbase + offset);
144a985ae9bSHans Petter Selasky 		} else {
14560d7ea3dSNathan Whitehorn 			*paddr = info->fb_pbase + offset;
14660d7ea3dSNathan Whitehorn #ifdef VM_MEMATTR_WRITE_COMBINING
14760d7ea3dSNathan Whitehorn 			*memattr = VM_MEMATTR_WRITE_COMBINING;
14860d7ea3dSNathan Whitehorn #endif
149a985ae9bSHans Petter Selasky 		}
15060d7ea3dSNathan Whitehorn 		return (0);
15160d7ea3dSNathan Whitehorn 	}
15260d7ea3dSNathan Whitehorn 
15360d7ea3dSNathan Whitehorn 	return (EINVAL);
1547a1a32c4SAleksandr Rybalko }
1557a1a32c4SAleksandr Rybalko 
1561365d077SJean-Sébastien Pédron void
1579e497e7bSAleksandr Rybalko vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
1589e497e7bSAleksandr Rybalko {
1599e497e7bSAleksandr Rybalko 	struct fb_info *info;
1609e497e7bSAleksandr Rybalko 	uint32_t c;
1619e497e7bSAleksandr Rybalko 	u_int o;
1629e497e7bSAleksandr Rybalko 
1639e497e7bSAleksandr Rybalko 	info = vd->vd_softc;
1649e497e7bSAleksandr Rybalko 	c = info->fb_cmap[color];
1659e497e7bSAleksandr Rybalko 	o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info);
1669e497e7bSAleksandr Rybalko 
167f1d2752fSNathan Whitehorn 	if (info->fb_flags & FB_FLAG_NOWRITE)
168f1d2752fSNathan Whitehorn 		return;
169f1d2752fSNathan Whitehorn 
1709ed297c8SNathan Whitehorn 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
1719ed297c8SNathan Whitehorn 
1729e497e7bSAleksandr Rybalko 	switch (FBTYPE_GET_BYTESPP(info)) {
1739e497e7bSAleksandr Rybalko 	case 1:
1749ed297c8SNathan Whitehorn 		vt_fb_mem_wr1(info, o, c);
1759e497e7bSAleksandr Rybalko 		break;
1769e497e7bSAleksandr Rybalko 	case 2:
1779ed297c8SNathan Whitehorn 		vt_fb_mem_wr2(info, o, c);
1789e497e7bSAleksandr Rybalko 		break;
1799e497e7bSAleksandr Rybalko 	case 3:
1809ed297c8SNathan Whitehorn 		vt_fb_mem_wr1(info, o, (c >> 16) & 0xff);
1819ed297c8SNathan Whitehorn 		vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff);
1829ed297c8SNathan Whitehorn 		vt_fb_mem_wr1(info, o + 2, c & 0xff);
1839e497e7bSAleksandr Rybalko 		break;
1849e497e7bSAleksandr Rybalko 	case 4:
1859ed297c8SNathan Whitehorn 		vt_fb_mem_wr4(info, o, c);
1869e497e7bSAleksandr Rybalko 		break;
1879e497e7bSAleksandr Rybalko 	default:
1889e497e7bSAleksandr Rybalko 		/* panic? */
1899e497e7bSAleksandr Rybalko 		return;
1909e497e7bSAleksandr Rybalko 	}
1919e497e7bSAleksandr Rybalko 
1929e497e7bSAleksandr Rybalko }
1939e497e7bSAleksandr Rybalko 
1941365d077SJean-Sébastien Pédron void
1959e497e7bSAleksandr Rybalko vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
1969e497e7bSAleksandr Rybalko     term_color_t color)
1979e497e7bSAleksandr Rybalko {
1989e497e7bSAleksandr Rybalko 	int x, y;
1999e497e7bSAleksandr Rybalko 
2009e497e7bSAleksandr Rybalko 	for (y = y1; y <= y2; y++) {
2019e497e7bSAleksandr Rybalko 		if (fill || (y == y1) || (y == y2)) {
2029e497e7bSAleksandr Rybalko 			for (x = x1; x <= x2; x++)
2039e497e7bSAleksandr Rybalko 				vt_fb_setpixel(vd, x, y, color);
2049e497e7bSAleksandr Rybalko 		} else {
2059e497e7bSAleksandr Rybalko 			vt_fb_setpixel(vd, x1, y, color);
2069e497e7bSAleksandr Rybalko 			vt_fb_setpixel(vd, x2, y, color);
2079e497e7bSAleksandr Rybalko 		}
2089e497e7bSAleksandr Rybalko 	}
2099e497e7bSAleksandr Rybalko }
2109e497e7bSAleksandr Rybalko 
2119e497e7bSAleksandr Rybalko void
21227cf7d04SAleksandr Rybalko vt_fb_blank(struct vt_device *vd, term_color_t color)
21327cf7d04SAleksandr Rybalko {
21427cf7d04SAleksandr Rybalko 	struct fb_info *info;
21527cf7d04SAleksandr Rybalko 	uint32_t c;
21660d7ea3dSNathan Whitehorn 	u_int o, h;
21727cf7d04SAleksandr Rybalko 
21827cf7d04SAleksandr Rybalko 	info = vd->vd_softc;
21927cf7d04SAleksandr Rybalko 	c = info->fb_cmap[color];
22027cf7d04SAleksandr Rybalko 
221f1d2752fSNathan Whitehorn 	if (info->fb_flags & FB_FLAG_NOWRITE)
222f1d2752fSNathan Whitehorn 		return;
223f1d2752fSNathan Whitehorn 
2249ed297c8SNathan Whitehorn 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
2259ed297c8SNathan Whitehorn 
22627cf7d04SAleksandr Rybalko 	switch (FBTYPE_GET_BYTESPP(info)) {
22727cf7d04SAleksandr Rybalko 	case 1:
22835e6436eSNathan Whitehorn 		for (h = 0; h < info->fb_height; h++)
22927cf7d04SAleksandr Rybalko 			for (o = 0; o < info->fb_stride; o++)
2309ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, h*info->fb_stride + o, c);
23127cf7d04SAleksandr Rybalko 		break;
23227cf7d04SAleksandr Rybalko 	case 2:
23335e6436eSNathan Whitehorn 		for (h = 0; h < info->fb_height; h++)
23427cf7d04SAleksandr Rybalko 			for (o = 0; o < info->fb_stride; o += 2)
2359ed297c8SNathan Whitehorn 				vt_fb_mem_wr2(info, h*info->fb_stride + o, c);
23627cf7d04SAleksandr Rybalko 		break;
23727cf7d04SAleksandr Rybalko 	case 3:
23835e6436eSNathan Whitehorn 		for (h = 0; h < info->fb_height; h++)
23927cf7d04SAleksandr Rybalko 			for (o = 0; o < info->fb_stride; o += 3) {
2409ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, h*info->fb_stride + o,
24160d7ea3dSNathan Whitehorn 				    (c >> 16) & 0xff);
2429ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, h*info->fb_stride + o + 1,
24360d7ea3dSNathan Whitehorn 				    (c >> 8) & 0xff);
2449ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, h*info->fb_stride + o + 2,
24560d7ea3dSNathan Whitehorn 				    c & 0xff);
24627cf7d04SAleksandr Rybalko 			}
24727cf7d04SAleksandr Rybalko 		break;
24827cf7d04SAleksandr Rybalko 	case 4:
24935e6436eSNathan Whitehorn 		for (h = 0; h < info->fb_height; h++)
25027cf7d04SAleksandr Rybalko 			for (o = 0; o < info->fb_stride; o += 4)
2519ed297c8SNathan Whitehorn 				vt_fb_mem_wr4(info, h*info->fb_stride + o, c);
25227cf7d04SAleksandr Rybalko 		break;
25327cf7d04SAleksandr Rybalko 	default:
25427cf7d04SAleksandr Rybalko 		/* panic? */
25527cf7d04SAleksandr Rybalko 		return;
25627cf7d04SAleksandr Rybalko 	}
25727cf7d04SAleksandr Rybalko }
25827cf7d04SAleksandr Rybalko 
259631bb572SJean-Sébastien Pédron void
260c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
261c285e4a5SJean-Sébastien Pédron     const uint8_t *pattern, const uint8_t *mask,
262c285e4a5SJean-Sébastien Pédron     unsigned int width, unsigned int height,
263c285e4a5SJean-Sébastien Pédron     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
26427cf7d04SAleksandr Rybalko {
26527cf7d04SAleksandr Rybalko 	struct fb_info *info;
26627cf7d04SAleksandr Rybalko 	uint32_t fgc, bgc, cc, o;
267*2c48063bSEd Maste 	int bpp, bpl, xi, yi;
268*2c48063bSEd Maste 	int bit, byte;
26927cf7d04SAleksandr Rybalko 
27027cf7d04SAleksandr Rybalko 	info = vd->vd_softc;
27127cf7d04SAleksandr Rybalko 	bpp = FBTYPE_GET_BYTESPP(info);
27227cf7d04SAleksandr Rybalko 	fgc = info->fb_cmap[fg];
27327cf7d04SAleksandr Rybalko 	bgc = info->fb_cmap[bg];
274*2c48063bSEd Maste 	bpl = (width + 7) / 8; /* Bytes per source line. */
27527cf7d04SAleksandr Rybalko 
276f1d2752fSNathan Whitehorn 	if (info->fb_flags & FB_FLAG_NOWRITE)
277f1d2752fSNathan Whitehorn 		return;
278f1d2752fSNathan Whitehorn 
2799ed297c8SNathan Whitehorn 	KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
2809ed297c8SNathan Whitehorn 
281*2c48063bSEd Maste 	/* Bound by right and bottom edges. */
282*2c48063bSEd Maste 	if (y + height > vw->vw_draw_area.tr_end.tp_row) {
283*2c48063bSEd Maste 		if (y >= vw->vw_draw_area.tr_end.tp_row)
284*2c48063bSEd Maste 			return;
285*2c48063bSEd Maste 		height = vw->vw_draw_area.tr_end.tp_row - y;
28627cf7d04SAleksandr Rybalko 	}
287*2c48063bSEd Maste 	if (x + width > vw->vw_draw_area.tr_end.tp_col) {
288*2c48063bSEd Maste 		if (x >= vw->vw_draw_area.tr_end.tp_col)
289*2c48063bSEd Maste 			return;
290*2c48063bSEd Maste 		width = vw->vw_draw_area.tr_end.tp_col - x;
291*2c48063bSEd Maste 	}
292*2c48063bSEd Maste 	for (yi = 0; yi < height; yi++) {
293*2c48063bSEd Maste 		for (xi = 0; xi < width; xi++) {
294*2c48063bSEd Maste 			byte = yi * bpl + xi / 8;
295*2c48063bSEd Maste 			bit = 0x80 >> (xi % 8);
296*2c48063bSEd Maste 			/* Skip pixel write, if mask bit not set. */
297*2c48063bSEd Maste 			if (mask != NULL && (mask[byte] & bit) == 0)
298*2c48063bSEd Maste 				continue;
299*2c48063bSEd Maste 			o = (y + yi) * info->fb_stride + (x + xi) * bpp;
300*2c48063bSEd Maste 			cc = pattern[byte] & bit ? fgc : bgc;
30127cf7d04SAleksandr Rybalko 
30227cf7d04SAleksandr Rybalko 			switch(bpp) {
30327cf7d04SAleksandr Rybalko 			case 1:
3049ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, o, cc);
30527cf7d04SAleksandr Rybalko 				break;
30627cf7d04SAleksandr Rybalko 			case 2:
3079ed297c8SNathan Whitehorn 				vt_fb_mem_wr2(info, o, cc);
30827cf7d04SAleksandr Rybalko 				break;
30927cf7d04SAleksandr Rybalko 			case 3:
31027cf7d04SAleksandr Rybalko 				/* Packed mode, so unaligned. Byte access. */
3119ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff);
3129ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff);
3139ed297c8SNathan Whitehorn 				vt_fb_mem_wr1(info, o + 2, cc & 0xff);
31427cf7d04SAleksandr Rybalko 				break;
31527cf7d04SAleksandr Rybalko 			case 4:
3169ed297c8SNathan Whitehorn 				vt_fb_mem_wr4(info, o, cc);
31727cf7d04SAleksandr Rybalko 				break;
31827cf7d04SAleksandr Rybalko 			default:
31927cf7d04SAleksandr Rybalko 				/* panic? */
32027cf7d04SAleksandr Rybalko 				break;
32127cf7d04SAleksandr Rybalko 			}
32227cf7d04SAleksandr Rybalko 		}
32327cf7d04SAleksandr Rybalko 	}
32427cf7d04SAleksandr Rybalko }
32527cf7d04SAleksandr Rybalko 
32627cf7d04SAleksandr Rybalko void
327c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
328c285e4a5SJean-Sébastien Pédron     const term_rect_t *area)
329c285e4a5SJean-Sébastien Pédron {
330c285e4a5SJean-Sébastien Pédron 	unsigned int col, row, x, y;
331c285e4a5SJean-Sébastien Pédron 	struct vt_font *vf;
332c285e4a5SJean-Sébastien Pédron 	term_char_t c;
333c285e4a5SJean-Sébastien Pédron 	term_color_t fg, bg;
334c285e4a5SJean-Sébastien Pédron 	const uint8_t *pattern;
335c285e4a5SJean-Sébastien Pédron 
336c285e4a5SJean-Sébastien Pédron 	vf = vw->vw_font;
337c285e4a5SJean-Sébastien Pédron 
338c285e4a5SJean-Sébastien Pédron 	for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
339c285e4a5SJean-Sébastien Pédron 		for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
340c285e4a5SJean-Sébastien Pédron 		    ++col) {
34183fbb296SJean-Sébastien Pédron 			x = col * vf->vf_width +
34283fbb296SJean-Sébastien Pédron 			    vw->vw_draw_area.tr_begin.tp_col;
34383fbb296SJean-Sébastien Pédron 			y = row * vf->vf_height +
34483fbb296SJean-Sébastien Pédron 			    vw->vw_draw_area.tr_begin.tp_row;
345c285e4a5SJean-Sébastien Pédron 
346c285e4a5SJean-Sébastien Pédron 			c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
347c285e4a5SJean-Sébastien Pédron 			pattern = vtfont_lookup(vf, c);
348c285e4a5SJean-Sébastien Pédron 			vt_determine_colors(c,
349c285e4a5SJean-Sébastien Pédron 			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
350c285e4a5SJean-Sébastien Pédron 
351c285e4a5SJean-Sébastien Pédron 			vt_fb_bitblt_bitmap(vd, vw,
352c285e4a5SJean-Sébastien Pédron 			    pattern, NULL, vf->vf_width, vf->vf_height,
353c285e4a5SJean-Sébastien Pédron 			    x, y, fg, bg);
354c285e4a5SJean-Sébastien Pédron 		}
355c285e4a5SJean-Sébastien Pédron 	}
356c285e4a5SJean-Sébastien Pédron 
357c285e4a5SJean-Sébastien Pédron #ifndef SC_NO_CUTPASTE
358c285e4a5SJean-Sébastien Pédron 	if (!vd->vd_mshown)
359c285e4a5SJean-Sébastien Pédron 		return;
360c285e4a5SJean-Sébastien Pédron 
361c285e4a5SJean-Sébastien Pédron 	term_rect_t drawn_area;
362c285e4a5SJean-Sébastien Pédron 
36384d623c6SJean-Sébastien Pédron 	drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
36484d623c6SJean-Sébastien Pédron 	drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
36584d623c6SJean-Sébastien Pédron 	drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
36684d623c6SJean-Sébastien Pédron 	drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
367c285e4a5SJean-Sébastien Pédron 
368c285e4a5SJean-Sébastien Pédron 	if (vt_is_cursor_in_area(vd, &drawn_area)) {
369c285e4a5SJean-Sébastien Pédron 		vt_fb_bitblt_bitmap(vd, vw,
370c285e4a5SJean-Sébastien Pédron 		    vd->vd_mcursor->map, vd->vd_mcursor->mask,
371c285e4a5SJean-Sébastien Pédron 		    vd->vd_mcursor->width, vd->vd_mcursor->height,
37284d623c6SJean-Sébastien Pédron 		    vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
37384d623c6SJean-Sébastien Pédron 		    vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
374c285e4a5SJean-Sébastien Pédron 		    vd->vd_mcursor_fg, vd->vd_mcursor_bg);
375c285e4a5SJean-Sébastien Pédron 	}
376c285e4a5SJean-Sébastien Pédron #endif
377c285e4a5SJean-Sébastien Pédron }
378c285e4a5SJean-Sébastien Pédron 
379c285e4a5SJean-Sébastien Pédron void
38027cf7d04SAleksandr Rybalko vt_fb_postswitch(struct vt_device *vd)
38127cf7d04SAleksandr Rybalko {
38227cf7d04SAleksandr Rybalko 	struct fb_info *info;
38327cf7d04SAleksandr Rybalko 
38427cf7d04SAleksandr Rybalko 	info = vd->vd_softc;
38527cf7d04SAleksandr Rybalko 
38627cf7d04SAleksandr Rybalko 	if (info->enter != NULL)
38727cf7d04SAleksandr Rybalko 		info->enter(info->fb_priv);
38827cf7d04SAleksandr Rybalko }
38927cf7d04SAleksandr Rybalko 
39027cf7d04SAleksandr Rybalko static int
39127cf7d04SAleksandr Rybalko vt_fb_init_cmap(uint32_t *cmap, int depth)
39227cf7d04SAleksandr Rybalko {
39327cf7d04SAleksandr Rybalko 
39427cf7d04SAleksandr Rybalko 	switch (depth) {
39527cf7d04SAleksandr Rybalko 	case 8:
39619e2ce2dSJean-Sébastien Pédron 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
39727cf7d04SAleksandr Rybalko 		    0x7, 5, 0x7, 2, 0x3, 0));
39827cf7d04SAleksandr Rybalko 	case 15:
39919e2ce2dSJean-Sébastien Pédron 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
40027cf7d04SAleksandr Rybalko 		    0x1f, 10, 0x1f, 5, 0x1f, 0));
40127cf7d04SAleksandr Rybalko 	case 16:
40219e2ce2dSJean-Sébastien Pédron 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
40327cf7d04SAleksandr Rybalko 		    0x1f, 11, 0x3f, 5, 0x1f, 0));
40427cf7d04SAleksandr Rybalko 	case 24:
40527cf7d04SAleksandr Rybalko 	case 32: /* Ignore alpha. */
40619e2ce2dSJean-Sébastien Pédron 		return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB,
40719e2ce2dSJean-Sébastien Pédron 		    0xff, 16, 0xff, 8, 0xff, 0));
40827cf7d04SAleksandr Rybalko 	default:
40927cf7d04SAleksandr Rybalko 		return (1);
41027cf7d04SAleksandr Rybalko 	}
41127cf7d04SAleksandr Rybalko }
41227cf7d04SAleksandr Rybalko 
41327cf7d04SAleksandr Rybalko int
41427cf7d04SAleksandr Rybalko vt_fb_init(struct vt_device *vd)
41527cf7d04SAleksandr Rybalko {
41627cf7d04SAleksandr Rybalko 	struct fb_info *info;
41727cf7d04SAleksandr Rybalko 	int err;
41827cf7d04SAleksandr Rybalko 
41927cf7d04SAleksandr Rybalko 	info = vd->vd_softc;
42027cf7d04SAleksandr Rybalko 	vd->vd_height = info->fb_height;
42127cf7d04SAleksandr Rybalko 	vd->vd_width = info->fb_width;
42276e2f976SJean-Sébastien Pédron 	vd->vd_video_dev = info->fb_video_dev;
42327cf7d04SAleksandr Rybalko 
4249ed297c8SNathan Whitehorn 	if (info->fb_size == 0)
4259ed297c8SNathan Whitehorn 		return (CN_DEAD);
4269ed297c8SNathan Whitehorn 
427a985ae9bSHans Petter Selasky 	if (info->fb_pbase == 0 && info->fb_vbase == 0)
4289ed297c8SNathan Whitehorn 		info->fb_flags |= FB_FLAG_NOMMAP;
4299ed297c8SNathan Whitehorn 
43027cf7d04SAleksandr Rybalko 	if (info->fb_cmsize <= 0) {
43127cf7d04SAleksandr Rybalko 		err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info));
43227cf7d04SAleksandr Rybalko 		if (err)
43327cf7d04SAleksandr Rybalko 			return (CN_DEAD);
43427cf7d04SAleksandr Rybalko 		info->fb_cmsize = 16;
43527cf7d04SAleksandr Rybalko 	}
43627cf7d04SAleksandr Rybalko 
43727cf7d04SAleksandr Rybalko 	/* Clear the screen. */
4382661dd32SNathan Whitehorn 	vd->vd_driver->vd_blank(vd, TC_BLACK);
43927cf7d04SAleksandr Rybalko 
44027cf7d04SAleksandr Rybalko 	/* Wakeup screen. KMS need this. */
44127cf7d04SAleksandr Rybalko 	vt_fb_postswitch(vd);
44227cf7d04SAleksandr Rybalko 
44327cf7d04SAleksandr Rybalko 	return (CN_INTERNAL);
44427cf7d04SAleksandr Rybalko }
44527cf7d04SAleksandr Rybalko 
44676e2f976SJean-Sébastien Pédron void
44776e2f976SJean-Sébastien Pédron vt_fb_fini(struct vt_device *vd, void *softc)
44876e2f976SJean-Sébastien Pédron {
44976e2f976SJean-Sébastien Pédron 
45076e2f976SJean-Sébastien Pédron 	vd->vd_video_dev = NULL;
45176e2f976SJean-Sébastien Pédron }
45276e2f976SJean-Sébastien Pédron 
45327cf7d04SAleksandr Rybalko int
45427cf7d04SAleksandr Rybalko vt_fb_attach(struct fb_info *info)
45527cf7d04SAleksandr Rybalko {
45627cf7d04SAleksandr Rybalko 
45727cf7d04SAleksandr Rybalko 	vt_allocate(&vt_fb_driver, info);
45827cf7d04SAleksandr Rybalko 
45927cf7d04SAleksandr Rybalko 	return (0);
46027cf7d04SAleksandr Rybalko }
46127cf7d04SAleksandr Rybalko 
46276e2f976SJean-Sébastien Pédron int
46376e2f976SJean-Sébastien Pédron vt_fb_detach(struct fb_info *info)
46476e2f976SJean-Sébastien Pédron {
46576e2f976SJean-Sébastien Pédron 
46676e2f976SJean-Sébastien Pédron 	vt_deallocate(&vt_fb_driver, info);
46776e2f976SJean-Sébastien Pédron 
46876e2f976SJean-Sébastien Pédron 	return (0);
46976e2f976SJean-Sébastien Pédron }
47076e2f976SJean-Sébastien Pédron 
47127cf7d04SAleksandr Rybalko void
4726dfa4578SAndriy Gapon vt_fb_suspend(struct vt_device *vd)
47327cf7d04SAleksandr Rybalko {
47427cf7d04SAleksandr Rybalko 
4756dfa4578SAndriy Gapon 	vt_suspend(vd);
47627cf7d04SAleksandr Rybalko }
47727cf7d04SAleksandr Rybalko 
47827cf7d04SAleksandr Rybalko void
4796dfa4578SAndriy Gapon vt_fb_resume(struct vt_device *vd)
48027cf7d04SAleksandr Rybalko {
48127cf7d04SAleksandr Rybalko 
4826dfa4578SAndriy Gapon 	vt_resume(vd);
48327cf7d04SAleksandr Rybalko }
484