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/fb/splash_bmp.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) 1999 Michael Smith <msmith@freebsd.org>
    5  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * $FreeBSD: releng/12.0/sys/dev/fb/splash_bmp.c 326255 2017-11-27 14:52:40Z pfg $
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/module.h>
   36 #include <sys/linker.h>
   37 #include <sys/fbio.h>
   38 
   39 #include <dev/fb/fbreg.h>
   40 #include <dev/fb/splashreg.h>
   41 #include <dev/fb/vgareg.h>
   42 
   43 #include <isa/isareg.h>
   44 
   45 #define FADE_TIMEOUT    15      /* sec */
   46 #define FADE_LEVELS     10
   47 
   48 static int splash_mode = -1;
   49 static int splash_on = FALSE;
   50 
   51 static int bmp_start(video_adapter_t *adp);
   52 static int bmp_end(video_adapter_t *adp);
   53 static int bmp_splash(video_adapter_t *adp, int on);
   54 static int bmp_Init(char *data, int swidth, int sheight, int sdepth);
   55 static int bmp_Draw(video_adapter_t *adp);
   56 
   57 static splash_decoder_t bmp_decoder = {
   58     "splash_bmp", bmp_start, bmp_end, bmp_splash, SPLASH_IMAGE,
   59 };
   60 
   61 SPLASH_DECODER(splash_bmp, bmp_decoder);
   62 
   63 static int 
   64 bmp_start(video_adapter_t *adp)
   65 {
   66     /* currently only 256-color modes are supported XXX */
   67     static int          modes[] = {
   68                         M_VESA_CG640x480,
   69                         M_VESA_CG800x600,
   70                         M_VESA_CG1024x768,
   71                         M_CG640x480,
   72                         /*
   73                          * As 320x200 doesn't generally look great,
   74                          * it's least preferred here.
   75                          */
   76                         M_VGA_CG320,
   77                         -1,
   78     };
   79     video_info_t        info;
   80     int                 i;
   81 
   82     if ((bmp_decoder.data == NULL) || (bmp_decoder.data_size <= 0)) {
   83         printf("splash_bmp: No bitmap file found\n");
   84         return ENODEV;
   85     }
   86     for (i = 0; modes[i] >= 0; ++i) {
   87         if ((vidd_get_info(adp, modes[i], &info) == 0) && 
   88             (bmp_Init((u_char *)bmp_decoder.data, info.vi_width,
   89                       info.vi_height, info.vi_depth) == 0))
   90             break;
   91     }
   92     splash_mode = modes[i];
   93     if (splash_mode < 0)
   94         printf("splash_bmp: No appropriate video mode found\n");
   95     if (bootverbose)
   96         printf("bmp_start(): splash_mode:%d\n", splash_mode);
   97     return ((splash_mode < 0) ? ENODEV : 0);
   98 }
   99 
  100 static int
  101 bmp_end(video_adapter_t *adp)
  102 {
  103     /* nothing to do */
  104     return 0;
  105 }
  106 
  107 static int
  108 bmp_splash(video_adapter_t *adp, int on)
  109 {
  110     static u_char       pal[256*3];
  111     static long         time_stamp;
  112     u_char              tpal[256*3];
  113     static int          fading = TRUE, brightness = FADE_LEVELS;
  114     struct timeval      tv;
  115     int                 i;
  116 
  117     if (on) {
  118         if (!splash_on) {
  119             /* set up the video mode and draw something */
  120             if (vidd_set_mode(adp, splash_mode))
  121                 return 1;
  122             if (bmp_Draw(adp))
  123                 return 1;
  124             vidd_save_palette(adp, pal);
  125             time_stamp = 0;
  126             splash_on = TRUE;
  127         }
  128         /*
  129          * This is a kludge to fade the image away.  This section of the 
  130          * code takes effect only after the system is completely up.
  131          * FADE_TIMEOUT should be configurable.
  132          */
  133         if (!cold) {
  134             getmicrotime(&tv);
  135             if (time_stamp == 0)
  136                 time_stamp = tv.tv_sec;
  137             if (tv.tv_sec > time_stamp + FADE_TIMEOUT) {
  138                 if (fading)
  139                     if (brightness == 0) {
  140                         fading = FALSE;
  141                         brightness++;
  142                     }
  143                     else brightness--;
  144                 else
  145                     if (brightness == FADE_LEVELS) {
  146                         fading = TRUE;
  147                         brightness--;
  148                     }
  149                     else brightness++;
  150                 for (i = 0; i < sizeof(pal); ++i) {
  151                     tpal[i] = pal[i] * brightness / FADE_LEVELS;
  152                 }
  153                 vidd_load_palette(adp, tpal);
  154                 time_stamp = tv.tv_sec;
  155             }
  156         }
  157         return 0;
  158     } else {
  159         /* the video mode will be restored by the caller */
  160         splash_on = FALSE;
  161         return 0;
  162     }
  163 }
  164 
  165 /*
  166 ** Code to handle Microsoft DIB (".BMP") format images.
  167 **
  168 ** Blame me (msmith@freebsd.org) if this is broken, not Soren.
  169 */
  170 
  171 typedef struct tagBITMAPFILEHEADER {    /* bmfh */
  172     u_short     bfType;
  173     int         bfSize;
  174     u_short     bfReserved1;
  175     u_short     bfReserved2;
  176     int         bfOffBits;
  177 } __packed BITMAPFILEHEADER;
  178 
  179 typedef struct tagBITMAPINFOHEADER {    /* bmih */
  180     int         biSize;
  181     int         biWidth;
  182     int         biHeight;
  183     short       biPlanes;
  184     short       biBitCount;
  185     int         biCompression;
  186     int         biSizeImage;
  187     int         biXPelsPerMeter;
  188     int         biYPelsPerMeter;
  189     int         biClrUsed;
  190     int         biClrImportant;
  191 } __packed BITMAPINFOHEADER;
  192 
  193 typedef struct tagRGBQUAD {     /* rgbq */
  194     u_char      rgbBlue;
  195     u_char      rgbGreen;
  196     u_char      rgbRed;
  197     u_char      rgbReserved;
  198 } __packed RGBQUAD;
  199 
  200 typedef struct tagBITMAPINFO {  /* bmi */
  201     BITMAPINFOHEADER    bmiHeader;
  202     RGBQUAD             bmiColors[256];
  203 } __packed BITMAPINFO;
  204 
  205 typedef struct tagBITMAPF
  206 {
  207     BITMAPFILEHEADER    bmfh;
  208     BITMAPINFO          bmfi;
  209 } __packed BITMAPF;
  210 
  211 #define BI_RGB          0
  212 #define BI_RLE8         1
  213 #define BI_RLE4         2
  214 
  215 /* 
  216 ** all we actually care about the image
  217 */
  218 typedef struct
  219 {
  220     int         width,height;           /* image dimensions */
  221     int         swidth,sheight;         /* screen dimensions for the current mode */
  222     u_char      depth;                  /* image depth (1, 4, 8, 24 bits) */
  223     u_char      sdepth;                 /* screen depth (1, 4, 8 bpp) */
  224     int         ncols;                  /* number of colours */
  225     u_char      palette[256][3];        /* raw palette data */
  226     u_char      format;                 /* one of the BI_* constants above */
  227     u_char      *data;                  /* pointer to the raw data */
  228     u_char      *index;                 /* running pointer to the data while drawing */
  229     u_char      *vidmem;                /* video memory allocated for drawing */
  230     video_adapter_t *adp;
  231     int         bank;
  232 } BMP_INFO;
  233 
  234 static BMP_INFO bmp_info;
  235 
  236 /*
  237 ** bmp_SetPix
  238 **
  239 ** Given (info), set the pixel at (x),(y) to (val) 
  240 **
  241 */
  242 static void
  243 bmp_SetPix(BMP_INFO *info, int x, int y, u_char val)
  244 {
  245     int         sofs, bofs;
  246     int         newbank;
  247 
  248     /*
  249      * range check to avoid explosions
  250      */
  251     if ((x < 0) || (x >= info->swidth) || (y < 0) || (y >= info->sheight))
  252         return;
  253     
  254     /* 
  255      * calculate offset into video memory;
  256      * because 0,0 is bottom-left for DIB, we have to convert.
  257      */
  258     sofs = ((info->height - (y+1) + (info->sheight - info->height) / 2) 
  259                 * info->adp->va_line_width);
  260     x += (info->swidth - info->width) / 2;
  261 
  262     switch(info->sdepth) {
  263     case 4:
  264     case 1:
  265         /* EGA/VGA planar modes */
  266         sofs += (x >> 3);
  267         newbank = sofs/info->adp->va_window_size;
  268         if (info->bank != newbank) {
  269             vidd_set_win_org(info->adp, newbank*info->adp->va_window_size);
  270             info->bank = newbank;
  271         }
  272         sofs %= info->adp->va_window_size;
  273         bofs = x & 0x7;                         /* offset within byte */
  274         outw(GDCIDX, (0x8000 >> bofs) | 0x08);  /* bit mask */
  275         outw(GDCIDX, (val << 8) | 0x00);        /* set/reset */
  276         *(info->vidmem + sofs) ^= 0xff;         /* read-modify-write */
  277         break;
  278 
  279     case 8:
  280         sofs += x;
  281         newbank = sofs/info->adp->va_window_size;
  282         if (info->bank != newbank) {
  283             vidd_set_win_org(info->adp, newbank*info->adp->va_window_size);
  284             info->bank = newbank;
  285         }
  286         sofs %= info->adp->va_window_size;
  287         *(info->vidmem+sofs) = val;
  288         break;
  289     }
  290 }
  291     
  292 /*
  293 ** bmp_DecodeRLE4
  294 **
  295 ** Given (data) pointing to a line of RLE4-format data and (line) being the starting
  296 ** line onscreen, decode the line.
  297 */
  298 static void
  299 bmp_DecodeRLE4(BMP_INFO *info, int line)
  300 {
  301     int         count;          /* run count */
  302     u_char      val;
  303     int         x,y;            /* screen position */
  304     
  305     x = 0;                      /* starting position */
  306     y = line;
  307     
  308     /* loop reading data */
  309     for (;;) {
  310         /*
  311          * encoded mode starts with a run length, and then a byte with
  312          * two colour indexes to alternate between for the run
  313          */
  314         if (*info->index) {
  315             for (count = 0; count < *info->index; count++, x++) {
  316                 if (count & 1) {                /* odd count, low nybble */
  317                     bmp_SetPix(info, x, y, *(info->index+1) & 0x0f);
  318                 } else {                        /* even count, high nybble */
  319                     bmp_SetPix(info, x, y, (*(info->index+1) >>4) & 0x0f);
  320                 }
  321             }
  322             info->index += 2;
  323         /* 
  324          * A leading zero is an escape; it may signal the end of the 
  325          * bitmap, a cursor move, or some absolute data.
  326          */
  327         } else {        /* zero tag may be absolute mode or an escape */
  328             switch (*(info->index+1)) {
  329             case 0:                             /* end of line */
  330                 info->index += 2;
  331                 return;
  332             case 1:                             /* end of bitmap */
  333                 info->index = NULL;
  334                 return;
  335             case 2:                             /* move */
  336                 x += *(info->index + 2);        /* new coords */
  337                 y += *(info->index + 3);
  338                 info->index += 4;
  339                 break;
  340             default:                            /* literal bitmap data */
  341                 for (count = 0; count < *(info->index + 1); count++, x++) {
  342                     val = *(info->index + 2 + (count / 2));     /* byte with nybbles */
  343                     if (count & 1) {
  344                         val &= 0xf;             /* get low nybble */
  345                     } else {
  346                         val = (val >> 4);       /* get high nybble */
  347                     }
  348                     bmp_SetPix(info, x, y, val);
  349                 }
  350                 /* warning, this depends on integer truncation, do not hand-optimise! */
  351                 info->index += 2 + ((count + 3) / 4) * 2;
  352                 break;
  353             }
  354         }
  355     }
  356 }
  357 
  358 /*
  359 ** bmp_DecodeRLE8
  360 ** Given (data) pointing to a line of RLE8-format data and (line) being the starting
  361 ** line onscreen, decode the line.
  362 */
  363 static void
  364 bmp_DecodeRLE8(BMP_INFO *info, int line)
  365 {
  366     int         count;          /* run count */
  367     int         x,y;            /* screen position */
  368     
  369     x = 0;                      /* starting position */
  370     y = line;
  371     
  372     /* loop reading data */
  373     for(;;) {
  374         /*
  375          * encoded mode starts with a run length, and then a byte with
  376          * two colour indexes to alternate between for the run
  377          */
  378         if (*info->index) {
  379             for (count = 0; count < *info->index; count++, x++)
  380                 bmp_SetPix(info, x, y, *(info->index+1));
  381             info->index += 2;
  382         /* 
  383          * A leading zero is an escape; it may signal the end of the 
  384          * bitmap, a cursor move, or some absolute data.
  385          */
  386         } else {        /* zero tag may be absolute mode or an escape */
  387             switch(*(info->index+1)) {
  388             case 0:                             /* end of line */
  389                 info->index += 2;
  390                 return;
  391             case 1:                             /* end of bitmap */
  392                 info->index = NULL;
  393                 return;
  394             case 2:                             /* move */
  395                 x += *(info->index + 2);        /* new coords */
  396                 y += *(info->index + 3);
  397                 info->index += 4;
  398                 break;
  399             default:                            /* literal bitmap data */
  400                 for (count = 0; count < *(info->index + 1); count++, x++)
  401                     bmp_SetPix(info, x, y, *(info->index + 2 + count));
  402                 /* must be an even count */
  403                 info->index += 2 + count + (count & 1);
  404                 break;
  405             }
  406         }
  407     }
  408 }
  409 
  410 /*
  411 ** bmp_DecodeLine
  412 **
  413 ** Given (info) pointing to an image being decoded, (line) being the line currently
  414 ** being displayed, decode a line of data.
  415 */
  416 static void
  417 bmp_DecodeLine(BMP_INFO *info, int line)
  418 {
  419     int         x;
  420     u_char      val, mask, *p;
  421 
  422     switch(info->format) {
  423     case BI_RGB:
  424         switch(info->depth) {
  425         case 8:
  426             for (x = 0; x < info->width; x++, info->index++)
  427                 bmp_SetPix(info, x, line, *info->index);
  428             info->index += 3 - (--x % 4);
  429             break;
  430         case 4:
  431             p = info->index;
  432             for (x = 0; x < info->width; x++) {
  433                 if (x & 1) {
  434                     val = *p & 0xf;     /* get low nybble */
  435                     p++;
  436                 } else {
  437                     val = *p >> 4;      /* get high nybble */
  438                 }
  439                 bmp_SetPix(info, x, line, val);
  440             }
  441             /* warning, this depends on integer truncation, do not hand-optimise! */
  442             info->index += ((x + 7) / 8) * 4;
  443             break;
  444         case 1:
  445             p = info->index;
  446             mask = 0x80;
  447             for (x = 0; x < info->width; x++) {
  448                 val = (*p & mask) ? 1 : 0;
  449                 mask >>= 1;
  450                 if (mask == 0) {
  451                     mask = 0x80;
  452                     p++;
  453                 }
  454                 bmp_SetPix(info, x, line, val);
  455             }
  456             /* warning, this depends on integer truncation, do not hand-optimise! */
  457             info->index += ((x + 31) / 32) * 4;
  458             break;
  459         }
  460         break;
  461     case BI_RLE4:
  462         bmp_DecodeRLE4(info, line);
  463         break;
  464     case BI_RLE8:
  465         bmp_DecodeRLE8(info, line);
  466         break;
  467     }
  468 }
  469 
  470 /*
  471 ** bmp_Init
  472 **
  473 ** Given a pointer (data) to the image of a BMP file, fill in bmp_info with what
  474 ** can be learnt from it.  Return nonzero if the file isn't usable.
  475 **
  476 ** Take screen dimensions (swidth), (sheight) and (sdepth) and make sure we
  477 ** can work with these.
  478 */
  479 static int
  480 bmp_Init(char *data, int swidth, int sheight, int sdepth)
  481 {
  482     BITMAPF     *bmf = (BITMAPF *)data;
  483     int         pind;
  484 
  485     bmp_info.data = NULL;       /* assume setup failed */
  486 
  487     /* check file ID */
  488     if (bmf->bmfh.bfType != 0x4d42) {
  489         printf("splash_bmp: not a BMP file\n");
  490         return(1);              /* XXX check word ordering for big-endian ports? */
  491     }
  492 
  493     /* do we understand this bitmap format? */
  494     if (bmf->bmfi.bmiHeader.biSize > sizeof(bmf->bmfi.bmiHeader)) {
  495         printf("splash_bmp: unsupported BMP format (size=%d)\n",
  496                 bmf->bmfi.bmiHeader.biSize);
  497         return(1);
  498     }
  499 
  500     /* save what we know about the screen */
  501     bmp_info.swidth = swidth;
  502     bmp_info.sheight = sheight;
  503     bmp_info.sdepth = sdepth;
  504 
  505     /* where's the data? */
  506     bmp_info.data = (u_char *)data + bmf->bmfh.bfOffBits;
  507 
  508     /* image parameters */
  509     bmp_info.width = bmf->bmfi.bmiHeader.biWidth;
  510     bmp_info.height = bmf->bmfi.bmiHeader.biHeight;
  511     bmp_info.depth = bmf->bmfi.bmiHeader.biBitCount;
  512     bmp_info.format = bmf->bmfi.bmiHeader.biCompression;
  513 
  514     switch(bmp_info.format) {   /* check compression format */
  515     case BI_RGB:
  516     case BI_RLE4:
  517     case BI_RLE8:
  518         break;
  519     default:
  520         printf("splash_bmp: unsupported compression format\n");
  521         return(1);              /* unsupported compression format */
  522     }
  523     
  524     /* palette details */
  525     bmp_info.ncols = (bmf->bmfi.bmiHeader.biClrUsed);
  526     bzero(bmp_info.palette,sizeof(bmp_info.palette));
  527     if (bmp_info.ncols == 0) {  /* uses all of them */
  528         bmp_info.ncols = 1 << bmf->bmfi.bmiHeader.biBitCount;
  529     }
  530     if ((bmp_info.height > bmp_info.sheight) ||
  531         (bmp_info.width > bmp_info.swidth) ||
  532         (bmp_info.ncols > (1 << sdepth))) {
  533         if (bootverbose)
  534             printf("splash_bmp: beyond screen capacity (%dx%d, %d colors)\n",
  535                    bmp_info.width, bmp_info.height, bmp_info.ncols);
  536         return(1);
  537     }
  538 
  539     /* read palette */
  540     for (pind = 0; pind < bmp_info.ncols; pind++) {
  541         bmp_info.palette[pind][0] = bmf->bmfi.bmiColors[pind].rgbRed;
  542         bmp_info.palette[pind][1] = bmf->bmfi.bmiColors[pind].rgbGreen;
  543         bmp_info.palette[pind][2] = bmf->bmfi.bmiColors[pind].rgbBlue;
  544     }
  545     return(0);
  546 }
  547 
  548 /*
  549 ** bmp_Draw
  550 **
  551 ** Render the image.  Return nonzero if that's not possible.
  552 **
  553 */
  554 static int
  555 bmp_Draw(video_adapter_t *adp)
  556 {
  557     int         line;
  558 #if 0
  559     int         i;
  560 #endif
  561 
  562     if (bmp_info.data == NULL) {        /* init failed, do nothing */
  563         return(1);
  564     }
  565     
  566     /* clear the screen */
  567     bmp_info.vidmem = (u_char *)adp->va_window;
  568     bmp_info.adp = adp;
  569     vidd_clear(adp);
  570     vidd_set_win_org(adp, 0);
  571     bmp_info.bank = 0;
  572 
  573     /* initialise the info structure for drawing */
  574     bmp_info.index = bmp_info.data;
  575     
  576     /* set the palette for our image */
  577     vidd_load_palette(adp, (u_char *)&bmp_info.palette);
  578 
  579 #if 0
  580     /* XXX: this is ugly, but necessary for EGA/VGA 1bpp/4bpp modes */
  581     if ((adp->va_type == KD_EGA) || (adp->va_type == KD_VGA)) {
  582         inb(adp->va_crtc_addr + 6);             /* reset flip-flop */
  583         outb(ATC, 0x14);
  584         outb(ATC, 0);
  585         for (i = 0; i < 16; ++i) {
  586             outb(ATC, i);
  587             outb(ATC, i);
  588         }
  589         inb(adp->va_crtc_addr + 6);             /* reset flip-flop */
  590         outb(ATC, 0x20);                        /* enable palette */
  591 
  592         outw(GDCIDX, 0x0f01);                   /* set/reset enable */
  593 
  594         if (bmp_info.sdepth == 1)
  595             outw(TSIDX, 0x0102);                /* unmask plane #0 */
  596     }
  597 #endif
  598 
  599     for (line = 0; (line < bmp_info.height) && bmp_info.index; line++) {
  600         bmp_DecodeLine(&bmp_info, line);
  601     }
  602     return(0);
  603 }

Cache object: 34eeee92b5300d2282209feb18a753f3


[ 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.