The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/vt/hw/fb/vt_fb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2013 The FreeBSD Foundation
    5  *
    6  * This software was developed by Aleksandr Rybalko under sponsorship from the
    7  * FreeBSD Foundation.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/malloc.h>
   37 #include <sys/queue.h>
   38 #include <sys/fbio.h>
   39 #include <sys/kernel.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 #include <vm/vm.h>
   45 #include <vm/pmap.h>
   46 
   47 static struct vt_driver vt_fb_driver = {
   48         .vd_name = "fb",
   49         .vd_init = vt_fb_init,
   50         .vd_fini = vt_fb_fini,
   51         .vd_blank = vt_fb_blank,
   52         .vd_bitblt_text = vt_fb_bitblt_text,
   53         .vd_invalidate_text = vt_fb_invalidate_text,
   54         .vd_bitblt_bmp = vt_fb_bitblt_bitmap,
   55         .vd_drawrect = vt_fb_drawrect,
   56         .vd_setpixel = vt_fb_setpixel,
   57         .vd_postswitch = vt_fb_postswitch,
   58         .vd_priority = VD_PRIORITY_GENERIC+10,
   59         .vd_fb_ioctl = vt_fb_ioctl,
   60         .vd_fb_mmap = vt_fb_mmap,
   61         .vd_suspend = vt_fb_suspend,
   62         .vd_resume = vt_fb_resume,
   63 };
   64 
   65 VT_DRIVER_DECLARE(vt_fb, vt_fb_driver);
   66 
   67 static void
   68 vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v)
   69 {
   70 
   71         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
   72         *(uint8_t *)(sc->fb_vbase + o) = v;
   73 }
   74 
   75 static void
   76 vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v)
   77 {
   78 
   79         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
   80         *(uint16_t *)(sc->fb_vbase + o) = v;
   81 }
   82 
   83 static void
   84 vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v)
   85 {
   86 
   87         KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o));
   88         *(uint32_t *)(sc->fb_vbase + o) = v;
   89 }
   90 
   91 int
   92 vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td)
   93 {
   94         struct fb_info *info;
   95         int error = 0;
   96 
   97         info = vd->vd_softc;
   98 
   99         switch (cmd) {
  100         case FBIOGTYPE:
  101                 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
  102                 break;
  103 
  104         case FBIO_GETWINORG:    /* get frame buffer window origin */
  105                 *(u_int *)data = 0;
  106                 break;
  107 
  108         case FBIO_GETDISPSTART: /* get display start address */
  109                 ((video_display_start_t *)data)->x = 0;
  110                 ((video_display_start_t *)data)->y = 0;
  111                 break;
  112 
  113         case FBIO_GETLINEWIDTH: /* get scan line width in bytes */
  114                 *(u_int *)data = info->fb_stride;
  115                 break;
  116 
  117         case FBIO_BLANK:        /* blank display */
  118                 if (vd->vd_driver->vd_blank == NULL)
  119                         return (ENODEV);
  120                 vd->vd_driver->vd_blank(vd, TC_BLACK);
  121                 break;
  122 
  123         case FBIO_GETRGBOFFS:   /* get RGB offsets */
  124                 if (info->fb_rgboffs.red == 0 && info->fb_rgboffs.green == 0 &&
  125                     info->fb_rgboffs.blue == 0)
  126                         return (ENOTTY);
  127                 memcpy((struct fb_rgboffs *)data, &info->fb_rgboffs,
  128                     sizeof(struct fb_rgboffs));
  129                 break;
  130 
  131         default:
  132                 error = ENOIOCTL;
  133                 break;
  134         }
  135 
  136         return (error);
  137 }
  138 
  139 int
  140 vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr,
  141     int prot, vm_memattr_t *memattr)
  142 {
  143         struct fb_info *info;
  144 
  145         info = vd->vd_softc;
  146 
  147         if (info->fb_flags & FB_FLAG_NOMMAP)
  148                 return (ENODEV);
  149 
  150         if (offset < info->fb_size) {
  151                 if (info->fb_pbase == 0) {
  152                         *paddr = vtophys((uint8_t *)info->fb_vbase + offset);
  153                 } else {
  154                         *paddr = info->fb_pbase + offset;
  155                         if (info->fb_flags & FB_FLAG_MEMATTR)
  156                                 *memattr = info->fb_memattr;
  157 #ifdef VM_MEMATTR_WRITE_COMBINING
  158                         else
  159                                 *memattr = VM_MEMATTR_WRITE_COMBINING;
  160 #endif
  161                 }
  162                 return (0);
  163         }
  164 
  165         return (EINVAL);
  166 }
  167 
  168 void
  169 vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color)
  170 {
  171         struct fb_info *info;
  172         uint32_t c;
  173         u_int o;
  174 
  175         info = vd->vd_softc;
  176         c = info->fb_cmap[color];
  177         o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info);
  178 
  179         if (info->fb_flags & FB_FLAG_NOWRITE)
  180                 return;
  181 
  182         KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
  183 
  184         switch (FBTYPE_GET_BYTESPP(info)) {
  185         case 1:
  186                 vt_fb_mem_wr1(info, o, c);
  187                 break;
  188         case 2:
  189                 vt_fb_mem_wr2(info, o, c);
  190                 break;
  191         case 3:
  192                 vt_fb_mem_wr1(info, o, (c >> 16) & 0xff);
  193                 vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff);
  194                 vt_fb_mem_wr1(info, o + 2, c & 0xff);
  195                 break;
  196         case 4:
  197                 vt_fb_mem_wr4(info, o, c);
  198                 break;
  199         default:
  200                 /* panic? */
  201                 return;
  202         }
  203 }
  204 
  205 void
  206 vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill,
  207     term_color_t color)
  208 {
  209         int x, y;
  210 
  211         for (y = y1; y <= y2; y++) {
  212                 if (fill || (y == y1) || (y == y2)) {
  213                         for (x = x1; x <= x2; x++)
  214                                 vt_fb_setpixel(vd, x, y, color);
  215                 } else {
  216                         vt_fb_setpixel(vd, x1, y, color);
  217                         vt_fb_setpixel(vd, x2, y, color);
  218                 }
  219         }
  220 }
  221 
  222 void
  223 vt_fb_blank(struct vt_device *vd, term_color_t color)
  224 {
  225         struct fb_info *info;
  226         uint32_t c;
  227         u_int o, h;
  228 
  229         info = vd->vd_softc;
  230         c = info->fb_cmap[color];
  231 
  232         if (info->fb_flags & FB_FLAG_NOWRITE)
  233                 return;
  234 
  235         KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
  236 
  237         switch (FBTYPE_GET_BYTESPP(info)) {
  238         case 1:
  239                 for (h = 0; h < info->fb_height; h++)
  240                         for (o = 0; o < info->fb_stride; o++)
  241                                 vt_fb_mem_wr1(info, h*info->fb_stride + o, c);
  242                 break;
  243         case 2:
  244                 for (h = 0; h < info->fb_height; h++)
  245                         for (o = 0; o < info->fb_stride - 1; o += 2)
  246                                 vt_fb_mem_wr2(info, h*info->fb_stride + o, c);
  247                 break;
  248         case 3:
  249                 for (h = 0; h < info->fb_height; h++)
  250                         for (o = 0; o < info->fb_stride - 2; o += 3) {
  251                                 vt_fb_mem_wr1(info, h*info->fb_stride + o,
  252                                     (c >> 16) & 0xff);
  253                                 vt_fb_mem_wr1(info, h*info->fb_stride + o + 1,
  254                                     (c >> 8) & 0xff);
  255                                 vt_fb_mem_wr1(info, h*info->fb_stride + o + 2,
  256                                     c & 0xff);
  257                         }
  258                 break;
  259         case 4:
  260                 for (h = 0; h < info->fb_height; h++)
  261                         for (o = 0; o < info->fb_stride - 3; o += 4)
  262                                 vt_fb_mem_wr4(info, h*info->fb_stride + o, c);
  263                 break;
  264         default:
  265                 /* panic? */
  266                 return;
  267         }
  268 }
  269 
  270 void
  271 vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
  272     const uint8_t *pattern, const uint8_t *mask,
  273     unsigned int width, unsigned int height,
  274     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
  275 {
  276         struct fb_info *info;
  277         uint32_t fgc, bgc, cc, o;
  278         int bpp, bpl, xi, yi;
  279         int bit, byte;
  280 
  281         info = vd->vd_softc;
  282         bpp = FBTYPE_GET_BYTESPP(info);
  283         fgc = info->fb_cmap[fg];
  284         bgc = info->fb_cmap[bg];
  285         bpl = (width + 7) / 8; /* Bytes per source line. */
  286 
  287         if (info->fb_flags & FB_FLAG_NOWRITE)
  288                 return;
  289 
  290         KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer"));
  291 
  292         /* Bound by right and bottom edges. */
  293         if (y + height > vw->vw_draw_area.tr_end.tp_row) {
  294                 if (y >= vw->vw_draw_area.tr_end.tp_row)
  295                         return;
  296                 height = vw->vw_draw_area.tr_end.tp_row - y;
  297         }
  298         if (x + width > vw->vw_draw_area.tr_end.tp_col) {
  299                 if (x >= vw->vw_draw_area.tr_end.tp_col)
  300                         return;
  301                 width = vw->vw_draw_area.tr_end.tp_col - x;
  302         }
  303         for (yi = 0; yi < height; yi++) {
  304                 for (xi = 0; xi < width; xi++) {
  305                         byte = yi * bpl + xi / 8;
  306                         bit = 0x80 >> (xi % 8);
  307                         /* Skip pixel write, if mask bit not set. */
  308                         if (mask != NULL && (mask[byte] & bit) == 0)
  309                                 continue;
  310                         o = (y + yi) * info->fb_stride + (x + xi) * bpp;
  311                         o += vd->vd_transpose;
  312                         cc = pattern[byte] & bit ? fgc : bgc;
  313 
  314                         switch(bpp) {
  315                         case 1:
  316                                 vt_fb_mem_wr1(info, o, cc);
  317                                 break;
  318                         case 2:
  319                                 vt_fb_mem_wr2(info, o, cc);
  320                                 break;
  321                         case 3:
  322                                 /* Packed mode, so unaligned. Byte access. */
  323                                 vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff);
  324                                 vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff);
  325                                 vt_fb_mem_wr1(info, o + 2, cc & 0xff);
  326                                 break;
  327                         case 4:
  328                                 vt_fb_mem_wr4(info, o, cc);
  329                                 break;
  330                         default:
  331                                 /* panic? */
  332                                 break;
  333                         }
  334                 }
  335         }
  336 }
  337 
  338 void
  339 vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
  340     const term_rect_t *area)
  341 {
  342         unsigned int col, row, x, y;
  343         struct vt_font *vf;
  344         term_char_t c;
  345         term_color_t fg, bg;
  346         const uint8_t *pattern;
  347         size_t z;
  348 
  349         vf = vw->vw_font;
  350 
  351         for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
  352                 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
  353                     ++col) {
  354                         x = col * vf->vf_width +
  355                             vw->vw_draw_area.tr_begin.tp_col;
  356                         y = row * vf->vf_height +
  357                             vw->vw_draw_area.tr_begin.tp_row;
  358 
  359                         c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
  360                         pattern = vtfont_lookup(vf, c);
  361                         vt_determine_colors(c,
  362                             VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
  363 
  364                         z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col;
  365                         if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) *
  366                             PIXEL_WIDTH(VT_FB_MAX_WIDTH))
  367                                 continue;
  368                         if (vd->vd_drawn && (vd->vd_drawn[z] == c) &&
  369                             vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) &&
  370                             vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg))
  371                                 continue;
  372 
  373                         vt_fb_bitblt_bitmap(vd, vw,
  374                             pattern, NULL, vf->vf_width, vf->vf_height,
  375                             x, y, fg, bg);
  376 
  377                         if (vd->vd_drawn)
  378                                 vd->vd_drawn[z] = c;
  379                         if (vd->vd_drawnfg)
  380                                 vd->vd_drawnfg[z] = fg;
  381                         if (vd->vd_drawnbg)
  382                                 vd->vd_drawnbg[z] = bg;
  383                 }
  384         }
  385 
  386 #ifndef SC_NO_CUTPASTE
  387         if (!vd->vd_mshown)
  388                 return;
  389 
  390         term_rect_t drawn_area;
  391 
  392         drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
  393         drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
  394         drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
  395         drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
  396 
  397         if (vt_is_cursor_in_area(vd, &drawn_area)) {
  398                 vt_fb_bitblt_bitmap(vd, vw,
  399                     vd->vd_mcursor->map, vd->vd_mcursor->mask,
  400                     vd->vd_mcursor->width, vd->vd_mcursor->height,
  401                     vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
  402                     vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
  403                     vd->vd_mcursor_fg, vd->vd_mcursor_bg);
  404         }
  405 #endif
  406 }
  407 
  408 void
  409 vt_fb_invalidate_text(struct vt_device *vd, const term_rect_t *area)
  410 {
  411         unsigned int col, row;
  412         size_t z;
  413 
  414         for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
  415                 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
  416                     ++col) {
  417                         z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col;
  418                         if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) *
  419                             PIXEL_WIDTH(VT_FB_MAX_WIDTH))
  420                                 continue;
  421                         if (vd->vd_drawn)
  422                                 vd->vd_drawn[z] = 0;
  423                         if (vd->vd_drawnfg)
  424                                 vd->vd_drawnfg[z] = 0;
  425                         if (vd->vd_drawnbg)
  426                                 vd->vd_drawnbg[z] = 0;
  427                 }
  428         }
  429 }
  430 
  431 void
  432 vt_fb_postswitch(struct vt_device *vd)
  433 {
  434         struct fb_info *info;
  435 
  436         info = vd->vd_softc;
  437 
  438         if (info->enter != NULL)
  439                 info->enter(info->fb_priv);
  440 }
  441 
  442 static int
  443 vt_fb_init_colors(struct fb_info *info)
  444 {
  445 
  446         switch (FBTYPE_GET_BPP(info)) {
  447         case 8:
  448                 return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
  449                     0x7, 5, 0x7, 2, 0x3, 0));
  450         case 15:
  451                 return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
  452                     0x1f, 10, 0x1f, 5, 0x1f, 0));
  453         case 16:
  454                 return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
  455                     0x1f, 11, 0x3f, 5, 0x1f, 0));
  456         case 24:
  457         case 32: /* Ignore alpha. */
  458                 return (vt_config_cons_colors(info, COLOR_FORMAT_RGB,
  459                     0xff, 16, 0xff, 8, 0xff, 0));
  460         default:
  461                 return (1);
  462         }
  463 }
  464 
  465 int
  466 vt_fb_init(struct vt_device *vd)
  467 {
  468         struct fb_info *info;
  469         u_int margin;
  470         int bg, err;
  471         term_color_t c;
  472 
  473         info = vd->vd_softc;
  474         vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height);
  475         margin = (info->fb_height - vd->vd_height) >> 1;
  476         vd->vd_transpose = margin * info->fb_stride;
  477         vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width);
  478         margin = (info->fb_width - vd->vd_width) >> 1;
  479         vd->vd_transpose += margin * (info->fb_bpp / NBBY);
  480         vd->vd_video_dev = info->fb_video_dev;
  481 
  482         if (info->fb_size == 0)
  483                 return (CN_DEAD);
  484 
  485         if (info->fb_pbase == 0 && info->fb_vbase == 0)
  486                 info->fb_flags |= FB_FLAG_NOMMAP;
  487 
  488         if (info->fb_cmsize <= 0) {
  489                 err = vt_fb_init_colors(info);
  490                 if (err)
  491                         return (CN_DEAD);
  492                 info->fb_cmsize = 16;
  493         }
  494 
  495         c = TC_BLACK;
  496         if (TUNABLE_INT_FETCH("teken.bg_color", &bg) != 0) {
  497                 if (bg == TC_WHITE)
  498                         bg |= TC_LIGHT;
  499                 c = bg;
  500         }
  501         /* Clear the screen. */
  502         vd->vd_driver->vd_blank(vd, c);
  503 
  504         /* Wakeup screen. KMS need this. */
  505         vt_fb_postswitch(vd);
  506 
  507         return (CN_INTERNAL);
  508 }
  509 
  510 void
  511 vt_fb_fini(struct vt_device *vd, void *softc)
  512 {
  513 
  514         vd->vd_video_dev = NULL;
  515 }
  516 
  517 int
  518 vt_fb_attach(struct fb_info *info)
  519 {
  520         int ret;
  521 
  522         ret = vt_allocate(&vt_fb_driver, info);
  523 
  524         return (ret);
  525 }
  526 
  527 int
  528 vt_fb_detach(struct fb_info *info)
  529 {
  530         int ret;
  531 
  532         ret = vt_deallocate(&vt_fb_driver, info);
  533 
  534         return (ret);
  535 }
  536 
  537 void
  538 vt_fb_suspend(struct vt_device *vd)
  539 {
  540 
  541         vt_suspend(vd);
  542 }
  543 
  544 void
  545 vt_fb_resume(struct vt_device *vd)
  546 {
  547 
  548         vt_resume(vd);
  549 }

Cache object: 14489e9f6a631f4ca671d5629d1f938d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.