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 44*7a1a32c4SAleksandr Rybalko static int vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, 45*7a1a32c4SAleksandr Rybalko struct thread *td); 46*7a1a32c4SAleksandr Rybalko static int vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, 47*7a1a32c4SAleksandr Rybalko vm_paddr_t *paddr, int prot, vm_memattr_t *memattr); 48*7a1a32c4SAleksandr Rybalko 4927cf7d04SAleksandr Rybalko static struct vt_driver vt_fb_driver = { 5027cf7d04SAleksandr Rybalko .vd_init = vt_fb_init, 5127cf7d04SAleksandr Rybalko .vd_blank = vt_fb_blank, 5227cf7d04SAleksandr Rybalko .vd_bitbltchr = vt_fb_bitbltchr, 5327cf7d04SAleksandr Rybalko .vd_postswitch = vt_fb_postswitch, 5427cf7d04SAleksandr Rybalko .vd_priority = VD_PRIORITY_GENERIC+10, 55*7a1a32c4SAleksandr Rybalko .vd_fb_ioctl = vt_fb_ioctl, 56*7a1a32c4SAleksandr Rybalko .vd_fb_mmap = vt_fb_mmap, 5727cf7d04SAleksandr Rybalko }; 5827cf7d04SAleksandr Rybalko 59*7a1a32c4SAleksandr Rybalko static int 60*7a1a32c4SAleksandr Rybalko vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 61*7a1a32c4SAleksandr Rybalko { 62*7a1a32c4SAleksandr Rybalko struct fb_info *info; 63*7a1a32c4SAleksandr Rybalko 64*7a1a32c4SAleksandr Rybalko info = vd->vd_softc; 65*7a1a32c4SAleksandr Rybalko 66*7a1a32c4SAleksandr Rybalko if (info->fb_ioctl == NULL) 67*7a1a32c4SAleksandr Rybalko return (-1); 68*7a1a32c4SAleksandr Rybalko 69*7a1a32c4SAleksandr Rybalko return (info->fb_ioctl(info->fb_cdev, cmd, data, 0, td)); 70*7a1a32c4SAleksandr Rybalko } 71*7a1a32c4SAleksandr Rybalko 72*7a1a32c4SAleksandr Rybalko static int vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, 73*7a1a32c4SAleksandr Rybalko vm_paddr_t *paddr, int prot, vm_memattr_t *memattr) 74*7a1a32c4SAleksandr Rybalko { 75*7a1a32c4SAleksandr Rybalko struct fb_info *info; 76*7a1a32c4SAleksandr Rybalko 77*7a1a32c4SAleksandr Rybalko info = vd->vd_softc; 78*7a1a32c4SAleksandr Rybalko 79*7a1a32c4SAleksandr Rybalko if (info->fb_ioctl == NULL) 80*7a1a32c4SAleksandr Rybalko return (ENXIO); 81*7a1a32c4SAleksandr Rybalko 82*7a1a32c4SAleksandr Rybalko return (info->fb_mmap(info->fb_cdev, offset, paddr, prot, memattr)); 83*7a1a32c4SAleksandr Rybalko } 84*7a1a32c4SAleksandr Rybalko 8527cf7d04SAleksandr Rybalko void 8627cf7d04SAleksandr Rybalko vt_fb_blank(struct vt_device *vd, term_color_t color) 8727cf7d04SAleksandr Rybalko { 8827cf7d04SAleksandr Rybalko struct fb_info *info; 8927cf7d04SAleksandr Rybalko uint32_t c; 9027cf7d04SAleksandr Rybalko u_int o; 9127cf7d04SAleksandr Rybalko 9227cf7d04SAleksandr Rybalko info = vd->vd_softc; 9327cf7d04SAleksandr Rybalko c = info->fb_cmap[color]; 9427cf7d04SAleksandr Rybalko 9527cf7d04SAleksandr Rybalko switch (FBTYPE_GET_BYTESPP(info)) { 9627cf7d04SAleksandr Rybalko case 1: 9727cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o++) 9827cf7d04SAleksandr Rybalko info->wr1(info, o, c); 9927cf7d04SAleksandr Rybalko break; 10027cf7d04SAleksandr Rybalko case 2: 10127cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o += 2) 10227cf7d04SAleksandr Rybalko info->wr2(info, o, c); 10327cf7d04SAleksandr Rybalko break; 10427cf7d04SAleksandr Rybalko case 3: 10527cf7d04SAleksandr Rybalko /* line 0 */ 10627cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o += 3) { 10727cf7d04SAleksandr Rybalko info->wr1(info, o, (c >> 16) & 0xff); 10827cf7d04SAleksandr Rybalko info->wr1(info, o + 1, (c >> 8) & 0xff); 10927cf7d04SAleksandr Rybalko info->wr1(info, o + 2, c & 0xff); 11027cf7d04SAleksandr Rybalko } 11127cf7d04SAleksandr Rybalko break; 11227cf7d04SAleksandr Rybalko case 4: 11327cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o += 4) 11427cf7d04SAleksandr Rybalko info->wr4(info, o, c); 11527cf7d04SAleksandr Rybalko break; 11627cf7d04SAleksandr Rybalko default: 11727cf7d04SAleksandr Rybalko /* panic? */ 11827cf7d04SAleksandr Rybalko return; 11927cf7d04SAleksandr Rybalko } 12027cf7d04SAleksandr Rybalko /* Copy line0 to all other lines. */ 12127cf7d04SAleksandr Rybalko /* XXX will copy with borders. */ 12227cf7d04SAleksandr Rybalko for (o = info->fb_stride; o < info->fb_size; o += info->fb_stride) { 12327cf7d04SAleksandr Rybalko info->copy(info, o, 0, info->fb_stride); 12427cf7d04SAleksandr Rybalko } 12527cf7d04SAleksandr Rybalko } 12627cf7d04SAleksandr Rybalko 12727cf7d04SAleksandr Rybalko void 12827cf7d04SAleksandr Rybalko vt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, 12927cf7d04SAleksandr Rybalko int bpl, vt_axis_t top, vt_axis_t left, unsigned int width, 13027cf7d04SAleksandr Rybalko unsigned int height, term_color_t fg, term_color_t bg) 13127cf7d04SAleksandr Rybalko { 13227cf7d04SAleksandr Rybalko struct fb_info *info; 13327cf7d04SAleksandr Rybalko uint32_t fgc, bgc, cc, o; 13427cf7d04SAleksandr Rybalko int c, l, bpp; 13527cf7d04SAleksandr Rybalko u_long line; 13627cf7d04SAleksandr Rybalko uint8_t b, m; 13727cf7d04SAleksandr Rybalko const uint8_t *ch; 13827cf7d04SAleksandr Rybalko 13927cf7d04SAleksandr Rybalko info = vd->vd_softc; 14027cf7d04SAleksandr Rybalko bpp = FBTYPE_GET_BYTESPP(info); 14127cf7d04SAleksandr Rybalko fgc = info->fb_cmap[fg]; 14227cf7d04SAleksandr Rybalko bgc = info->fb_cmap[bg]; 14327cf7d04SAleksandr Rybalko b = m = 0; 14427cf7d04SAleksandr Rybalko if (bpl == 0) 14527cf7d04SAleksandr Rybalko bpl = (width + 7) >> 3; /* Bytes per sorce line. */ 14627cf7d04SAleksandr Rybalko 14727cf7d04SAleksandr Rybalko /* Don't try to put off screen pixels */ 14827cf7d04SAleksandr Rybalko if (((left + width) > info->fb_width) || ((top + height) > 14927cf7d04SAleksandr Rybalko info->fb_height)) 15027cf7d04SAleksandr Rybalko return; 15127cf7d04SAleksandr Rybalko 15227cf7d04SAleksandr Rybalko line = (info->fb_stride * top) + (left * bpp); 15327cf7d04SAleksandr Rybalko for (l = 0; l < height; l++) { 15427cf7d04SAleksandr Rybalko ch = src; 15527cf7d04SAleksandr Rybalko for (c = 0; c < width; c++) { 15627cf7d04SAleksandr Rybalko if (c % 8 == 0) 15727cf7d04SAleksandr Rybalko b = *ch++; 15827cf7d04SAleksandr Rybalko else 15927cf7d04SAleksandr Rybalko b <<= 1; 16027cf7d04SAleksandr Rybalko if (mask != NULL) { 16127cf7d04SAleksandr Rybalko if (c % 8 == 0) 16227cf7d04SAleksandr Rybalko m = *mask++; 16327cf7d04SAleksandr Rybalko else 16427cf7d04SAleksandr Rybalko m <<= 1; 16527cf7d04SAleksandr Rybalko /* Skip pixel write, if mask has no bit set. */ 16627cf7d04SAleksandr Rybalko if ((m & 0x80) == 0) 16727cf7d04SAleksandr Rybalko continue; 16827cf7d04SAleksandr Rybalko } 16927cf7d04SAleksandr Rybalko o = line + (c * bpp); 17027cf7d04SAleksandr Rybalko cc = b & 0x80 ? fgc : bgc; 17127cf7d04SAleksandr Rybalko 17227cf7d04SAleksandr Rybalko switch(bpp) { 17327cf7d04SAleksandr Rybalko case 1: 17427cf7d04SAleksandr Rybalko info->wr1(info, o, cc); 17527cf7d04SAleksandr Rybalko break; 17627cf7d04SAleksandr Rybalko case 2: 17727cf7d04SAleksandr Rybalko info->wr2(info, o, cc); 17827cf7d04SAleksandr Rybalko break; 17927cf7d04SAleksandr Rybalko case 3: 18027cf7d04SAleksandr Rybalko /* Packed mode, so unaligned. Byte access. */ 18127cf7d04SAleksandr Rybalko info->wr1(info, o, (cc >> 16) & 0xff); 18227cf7d04SAleksandr Rybalko info->wr1(info, o + 1, (cc >> 8) & 0xff); 18327cf7d04SAleksandr Rybalko info->wr1(info, o + 2, cc & 0xff); 18427cf7d04SAleksandr Rybalko break; 18527cf7d04SAleksandr Rybalko case 4: 18627cf7d04SAleksandr Rybalko info->wr4(info, o, cc); 18727cf7d04SAleksandr Rybalko break; 18827cf7d04SAleksandr Rybalko default: 18927cf7d04SAleksandr Rybalko /* panic? */ 19027cf7d04SAleksandr Rybalko break; 19127cf7d04SAleksandr Rybalko } 19227cf7d04SAleksandr Rybalko } 19327cf7d04SAleksandr Rybalko line += info->fb_stride; 19427cf7d04SAleksandr Rybalko src += bpl; 19527cf7d04SAleksandr Rybalko } 19627cf7d04SAleksandr Rybalko } 19727cf7d04SAleksandr Rybalko 19827cf7d04SAleksandr Rybalko void 19927cf7d04SAleksandr Rybalko vt_fb_postswitch(struct vt_device *vd) 20027cf7d04SAleksandr Rybalko { 20127cf7d04SAleksandr Rybalko struct fb_info *info; 20227cf7d04SAleksandr Rybalko 20327cf7d04SAleksandr Rybalko info = vd->vd_softc; 20427cf7d04SAleksandr Rybalko 20527cf7d04SAleksandr Rybalko if (info->enter != NULL) 20627cf7d04SAleksandr Rybalko info->enter(info->fb_priv); 20727cf7d04SAleksandr Rybalko } 20827cf7d04SAleksandr Rybalko 20927cf7d04SAleksandr Rybalko static int 21027cf7d04SAleksandr Rybalko vt_fb_init_cmap(uint32_t *cmap, int depth) 21127cf7d04SAleksandr Rybalko { 21227cf7d04SAleksandr Rybalko 21327cf7d04SAleksandr Rybalko switch (depth) { 21427cf7d04SAleksandr Rybalko case 8: 21527cf7d04SAleksandr Rybalko return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 21627cf7d04SAleksandr Rybalko 0x7, 5, 0x7, 2, 0x3, 0)); 21727cf7d04SAleksandr Rybalko case 15: 21827cf7d04SAleksandr Rybalko return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 21927cf7d04SAleksandr Rybalko 0x1f, 10, 0x1f, 5, 0x1f, 0)); 22027cf7d04SAleksandr Rybalko case 16: 22127cf7d04SAleksandr Rybalko return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 22227cf7d04SAleksandr Rybalko 0x1f, 11, 0x3f, 5, 0x1f, 0)); 22327cf7d04SAleksandr Rybalko case 24: 22427cf7d04SAleksandr Rybalko case 32: /* Ignore alpha. */ 22527cf7d04SAleksandr Rybalko return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 22627cf7d04SAleksandr Rybalko 0xff, 0, 0xff, 8, 0xff, 16)); 22727cf7d04SAleksandr Rybalko default: 22827cf7d04SAleksandr Rybalko return (1); 22927cf7d04SAleksandr Rybalko } 23027cf7d04SAleksandr Rybalko } 23127cf7d04SAleksandr Rybalko 23227cf7d04SAleksandr Rybalko int 23327cf7d04SAleksandr Rybalko vt_fb_init(struct vt_device *vd) 23427cf7d04SAleksandr Rybalko { 23527cf7d04SAleksandr Rybalko struct fb_info *info; 23627cf7d04SAleksandr Rybalko int err; 23727cf7d04SAleksandr Rybalko 23827cf7d04SAleksandr Rybalko info = vd->vd_softc; 23927cf7d04SAleksandr Rybalko vd->vd_height = info->fb_height; 24027cf7d04SAleksandr Rybalko vd->vd_width = info->fb_width; 24127cf7d04SAleksandr Rybalko 24227cf7d04SAleksandr Rybalko if (info->fb_cmsize <= 0) { 24327cf7d04SAleksandr Rybalko err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 24427cf7d04SAleksandr Rybalko if (err) 24527cf7d04SAleksandr Rybalko return (CN_DEAD); 24627cf7d04SAleksandr Rybalko info->fb_cmsize = 16; 24727cf7d04SAleksandr Rybalko } 24827cf7d04SAleksandr Rybalko 24927cf7d04SAleksandr Rybalko /* Clear the screen. */ 25027cf7d04SAleksandr Rybalko vt_fb_blank(vd, TC_BLACK); 25127cf7d04SAleksandr Rybalko 25227cf7d04SAleksandr Rybalko /* Wakeup screen. KMS need this. */ 25327cf7d04SAleksandr Rybalko vt_fb_postswitch(vd); 25427cf7d04SAleksandr Rybalko 25527cf7d04SAleksandr Rybalko return (CN_INTERNAL); 25627cf7d04SAleksandr Rybalko } 25727cf7d04SAleksandr Rybalko 25827cf7d04SAleksandr Rybalko int 25927cf7d04SAleksandr Rybalko vt_fb_attach(struct fb_info *info) 26027cf7d04SAleksandr Rybalko { 26127cf7d04SAleksandr Rybalko 26227cf7d04SAleksandr Rybalko vt_allocate(&vt_fb_driver, info); 26327cf7d04SAleksandr Rybalko 26427cf7d04SAleksandr Rybalko return (0); 26527cf7d04SAleksandr Rybalko } 26627cf7d04SAleksandr Rybalko 26727cf7d04SAleksandr Rybalko void 26827cf7d04SAleksandr Rybalko vt_fb_resume(void) 26927cf7d04SAleksandr Rybalko { 27027cf7d04SAleksandr Rybalko 27127cf7d04SAleksandr Rybalko vt_resume(); 27227cf7d04SAleksandr Rybalko } 27327cf7d04SAleksandr Rybalko 27427cf7d04SAleksandr Rybalko void 27527cf7d04SAleksandr Rybalko vt_fb_suspend(void) 27627cf7d04SAleksandr Rybalko { 27727cf7d04SAleksandr Rybalko 27827cf7d04SAleksandr Rybalko vt_suspend(); 27927cf7d04SAleksandr Rybalko } 280